We're going to start. All right, thanks, everybody, for sticking around. We are going to present Unpredictable Continuous Deployment. And we're going to talk about all the painful lessons that we've learned along our journey towards a predictable continuous deployment with Drupal. And how to hopefully inspire you to make your environments and your deployments rock. So the presentations divided into essentially three sections, lessons in doing things the wrong way, components of good predictable deployment. So we're going to share some of the things that we started doing wrong many, many years ago. And hopefully, it will be a group hug. And you guys will be kind with us and remember some of the pain points that you've gone through, some of the ways in which we've attempted and are continuing to attempt to make that process better for everybody involved. And of course, how we do it with Drupal. So what this presentation is not about.  But of course, I hope that you stay. We're definitely not going to talk about tools. There's a lot of tools discussion. There have been a lot of tools discussions here. So we are not going to specifically provide tools, code examples, definitely no live demos, as you have seen in our 10 minute slide presentation set up, we're not going to try to attempt that right now. And we are not going to be very specific about prescribing the frameworks and how you do that. There are many, many ways of doing that. Obviously, there are sponsors here that have created an opinionated way of making this easier. We're not going to provide an opinionated way of doing it, which is going to talk about the processes that we've had to go on through and an approach that we take to make that happen. All right, so about us, I am Andy Kuharski. I am the president and founder of Promet Source. And I make it really easy for you to follow me on Twitter. It's a Kuharski. I know you guys all know how to spell that. So I'm just going to leave it at that. I'll put it up at the end of the presentation. I'm Johnny Fox. I'm the CTO of Promet. I've been with Promet for six years. I lead the team that has suffered with, struggled, and developed our continuous integration process. We're not sure about sharing our pain, huh? So a little bit about us. We are a full stack and full service development, Drupal development shop in Chicago. We're pretty distributed. We also offer services around training. So we have a training practice and as well as accessibility testing. The one thing that we started doing very early on, and we've been working with Drupal since 2008. So we still have a Drupal 5 site running in production somewhere out there. Yeah, thanks, somebody's impressed with that. We have taken on support of Drupal websites that we did not build from the very beginning. So we have seen things. We have seen a lot of things. We have taken on sites that we did not build. We take on sites that are in any environment, any hosting environment, internal hosting environments. So we have learned and we had to adapt to that reality. That is something that we have chosen to do strategically. And as a result, we have seen a lot of different, and we had to adapt to a lot of different ways. Or a lot of different ways in which Drupal sites were built and we had to adapt to our clients' needs. All right, so who are you? We want to know about you. Which Lego, which of these Lego characters represents you? Please raise your hand if you are a developer. Ooh, that's a majority in here. All right, please raise your hand if you are a systems engineer or ops person. Okay, that's pretty decent. And sorry about this characterization. If you are a product owner, a project manager, a business owner, please raise your hand. All right, I will raise my hand. That's me as well. Well, thank you. I had to throw in some logo pieces and a slide, right? That's necessary. So why should you care about CI and CD? Obviously you're in here and you care about it by attending these sessions. We're not going to define exactly what it is. Michelle Kretche's earlier presentation did a pretty good job of describing that and her journey into learning that. I highly recommend that. Development obviously cares about deploying building code and deploying features quickly. Operations cares about maintaining current state and making sure that uptime is maintained, that sites respond quickly and not many changes cause the beepers and the pagers. Ooh, I just said beepers. I'm old. Your phone to vibrate, pager duty. That's a good pager, right? So if we had a magic wand, right, whether you're an ops or a product owner or a project manager or a developer, you could walk up to your desk, say, Alexa, please deploy version dev v2.01.5 to my staging environment of this project and it would just happen. I actually have seen this happen on a demo. It did work. It was a live demo. I'm pretty sure that was a live demo. So that's the magic wand, right? And where did we start off? Where did we do things? I've been involved in deploying software for about 20 years, obviously prior to droop over deploying enterprise systems, but custom-built applications and for about 15 years, websites. So this is where you guys hopefully will see have suffered. Well, hopefully we'll display public offering or suffering that we have experienced deploying software manually, right? So do you remember those days ever or has anybody had to move files around from one server to another, making sure that you got the right files and you didn't script it and then you forgot a file, you got a long version. That was not fun, right? Running database scripts. Or have you ever run into testing your code in a environment that you think is just like production? Johnny, do you remember that one time where we were running that, we followed all the right steps. We thought we had the exact replica of the production. We asked the client for the Nginx version, sorry, it was an Apache version. The LAMP stack was exactly the same. The project had a tight deadline. We ran, we pushed it to production, big unveil, total fail. Like, wait a second, why? We tried to take these steps. We banged our heads against, hopefully our presentation of this play would not fail. We banged our heads against the wall for a while, only to find out that our client was running a LAMP stack emulator on a mainframe. Did not provide us with a testing environment. They said, don't worry, it's gonna be the same. No worries. So we've got some scars from that. That's why we're very passionate about making sure that the target of your testing environment is the same as the test environment. And more, has anybody ever had to receive a push script that's in an email that instructs you this manual clicks that you have to take? Okay, I know you guys are way above that. So hopefully we'll share our pain. That has happened to us before. So we really try to make sure that we don't do that. So what are the principles around what we've been doing and how we try to make our teams' lives easier, better, and funner? It's not a word, by the way, more fun. So we wanna be able to make sure that the package itself is tested. The package of release is tested. So it's reliable, right? It's reliable and repeatable. There's no better feeling from project managers or product owners or talking to a client that says, we're going, we do a build from scratch every single day. I know that this software will build. I know that it will run because that's predictable, that's reliable. We have a saying around Promat that says we love lazy developers. We do, and what we mean by that is that we love for everyone to automate stuff so you don't have to do the mind-numbing things over and over again. So automate whatever you can as often as you can. Obviously, keep everything in version control. We'd also like to bring the pain forward. So if it's something that is painful, let's make sure that we have a good retro about it. Let's talk about it. What are the challenges to doing the things that we need to do, whether it's an environment version or whether it's having a mainframe run on your local, how can we get past those things? Those need to be brought up and the risks need to be identified. We need to talk about how we're gonna get around that or what happens if something goes wrong. Build quality in, so everybody's job is to build quality in. Testing is obviously a big part of what we do, so we're gonna talk a lot about that. And continuous improvement, right? So make sure you listen to everyone and everybody. When you do your retrospectives, it's a safe environment. It's a learning environment and everybody should be encouraged and understand they can speak freely without feeling like you're attacking somebody because that's where you really learn the lessons that need to apply to the things that you're gonna do to make things better. So we have a number of resources that we look at and we pay attention to. I also want to emphasize that dev ops is a big cultural thing and it makes things better in your culture, right? When releases go out without stress and when you buy into the process, things culturally are better. This is from a study that was, I think released last year, talks about organizations who adapt. Dev Ops practices, fantastic, okay, great. So great results, unbelievable results, 200 times more code releases for high-performing organizations. This is a tongue twister for me, the other point from the product managers. Teams that adopt high-performing dev ops cultures are twice as likely to recommend other people to work with your company. So it's worth buying into that and if you need to convince somebody that we need to spend more time on building your automated testing or better push process, feel free to find that study. It just, this talks a little bit about what high IT performers are. So being able to deploy frequently that also has to do with making sure to deploy. Don't try to do the big monolithic deploys, limit what you're deploying so you can be testable. Failure rates are better, mean time to resolve and so on. All right, so we're gonna now talk about Predictable. Is that from it? All right, thanks, Andy. First I wanna apologize for the title Predictable Deployment because you can still have Predictable Deployment without continuous integration. I can predict you're gonna fail equically. You're going to have some days when your server is just a smoldering crater of why is this not working? The classic, it worked on my local why is it not here? That's Predictable. What we're really talking about is how do we get a Predictable successful deployment? And that's a struggle. There's some kind of basic tenants and my goal here today is to pass on what we adopt as those tenants give you a little bit of history. One of those is that you have a formal workflow process that we use the local development, dev staging, production workflow. There are a couple workflows where we have where we actually introduce another step of a client QA environment. I know that there's a couple of the platforms as a service that offer that to be able to see individual releases. Where we started was, as Andy mentioned, 2008, we saw the need that as we were deploying that we needed to have repeatable environments and we needed to have a way that those environments were the same. So in 2010, we were one of the first people to come out with Chef, which is Chef is a server configuration management tool. It can also be used to configure applications, but this was very early when we were starting. Only start. What I wanted to show is a little bit is that as you're on your continuous integration, continuous deployment journey, don't be afraid to get started, like start small and build on it. I know we have a lot of developers so a dancing analogy doesn't work, but you learn one step and then you learn the next step and you build on that. So as we worked over time, we kept adding a piece. So very much kind of an agile, you say, well, features and Chef, and now we need some build scripts and now we need get flow. And in here, you can see we changed configuration management, we went to Ansible, we've used different places alone. So what I really want you to take away is start somewhere, start today and add pieces onto it. In our environment, you need to be learning as you're working. From the continuous delivery book that Andy showed, we've adopted some CI principles. There's some of these that I think are, all of these are important and all of these are goals of what you should have. You can't have continuous integration without revision control. I can't imagine anyone doing development that way. You wanna automate the things. We've already talked about testing in the clone of production and really testing in the clone of production is all the way up and down the stack. You want to replicate that environment as much as you can. Frequent commits, putting all the code together. Our team is spread out across. We also have an office in the Philippines. We have a development team there. We work with people all over the US. We're spread out. There may be multiple people working on a project and just having one person's code sitting there not knowing whether or not it builds is a real issue for us. So we use HipChat as our platform for communication across the company. And that addresses code consolidations, build availability, and test availability. What I'm showing here is inside of our HipChat we're actually able to see and for each project there is a room that's there. So our commits from GitHub when the project is being built, if that succeed fails, succeeds, we're able to see that immediately. We're able to see the results of the test. Those links are all piped into there and that happens throughout the day.  Okay, call the next person. Say you're working on this other feature, is that okay? You can see the status of it in real time. As a developer, as a solutions architect you're able to see what's happening as well. So some of you may be thinking, well you may have a fairytale life, you may have been very good in the prior life and you're very blessed and you have really the same environment you deploy to all the time that you're deploying to Acquia or to Pantheon or you work at a place where you have, we're all on CentOS, we know what version of PHP we're on, we don't have to work like that. If you did something very bad in your prior life you may wind up at an agency that supports many websites, Promet supports hundreds of websites. I wanna share with you a little bit of the complexity that we run into, so we wind up with a few operating systems to support. And the great thing about operating systems is not only, it's not just Linux, it's which flavor of Linux? Is it Debian or Red Hat? Is it SUSE, Oracle Linux for anyone that's not worked with it is different even though it's on Red Hat? We also support client sites under Windows Server and then you got on a layer of well which database are you working? How do you optimize that database? If we wanna be a little bit more complex then we wind up with the hosting platforms, could be Google Cloud, could be Azure, could be Acquia or Pantheon and all of these are great platforms. I dream of a day when we all deploy and then that there's not variability between that. One of the things we see is that for each one of these platforms, there's a set of different hooks, so spinning up a server on rack space is different than Linux. That metaphor doesn't apply to platform but we still need to develop our Drupal so that we can deploy there. You have the additional complexity of Terminus is not the same as what you do on Acquia. Some of the platforms have modules that are specific that need to be ran to manage varnish on their environment that's different. This is a really kind of wicked problem. So to make it more fun, then you can layer on what services are you connected to. We've had really a lot of fun with Shibboleth. It has to have a daemon that runs in Linux to connect to. If you're not testing this, if you're not looking at that, you can just expect the client's gonna call and say why can't I log into the server? What was that change? Same thing with varnish, maybe you're working on a platform, a client controls it. There's a varnish upgrade from 2.2 to 2.4. I'm just sure with you the VCL files are different on those. Like you have to be testing. So it's a really complex problem for every different client. So remember, like a couple hundred projects to support. And all of these involve different sets of combinations of these. So maybe one CentOS, PHP 5.6. Some clients are still on 5.2. I know it's crazy, but you may be in a large enterprise environment. There's security concerns there. That's just the way they run. They're gonna be on 5.2. No button can change it. And that's what you have to deal with. So to address this on our side, we started out with, we realized that well, we just need, it's just a Drupal, right? Drupal is just PHP and I need MySQL and I need a web server. So Map, Zap, one of those solutions. Like that'll work. Pretty soon we got into, well, but you're working multiple projects. So you need to be able to have something that's portable that replicates that environment. So we, virtualization came along. We went to virtual box. Just almost immediately pulled Vagrant on top of that so that we had a little bit more control of the configuration of boxes. Went through a round of what is quick in Vagrant. So with Vagrant and Drupal VM, one of the challenges that we have is we have an office overseas. We have people that work remote on places that have slow connections. Anything where you're loading the entire box and the whole stack and that has to be built each time you build the environment that can add a lot of overhead. If you're in the U.S. and you have gigabit internet, you're set. If you have a 10 megabit connection and you're in Asia and you've got to pull something down, you're talking about something in the U.S. that could happen maybe in 15 minutes, takes you four hours. So today what we're using is Docker. We found that's more portable. It's quicker for us to use. And we'll see what comes next with containerization. Second part you really have to have is a CI server. There's a number of these. They're all, I think they're all good choices. I have trouble, we made a choice internally because of what our skills are. We have a dedicated DevOps team. As you've seen, we have kind of this complex topography of things that we deploy to. So we need really granular control over that. And we have settled on Jenkins. We could have an argument about which one's better. I say pick one that fits your organization. Testing, why do I have testing here? So continuous integration without any testing is just automating your failures. It does you no good to build a server and no to build your application and not know if it succeeds. And I'm sure no one here has had when you build the Drupal and I've changed something on a few pages. I need to make a few menu tweaks. I've moved a block around. And then I look at that, we test that, we deploy it and there's some other page somewhere that is totally broken from the result of those changes. Anyone have that? Yeah, I mean, you're in Drupal. All of you need to raise your hand.  It's terrible. Humans are terrible at it. Even on the best days, it's slow, it's expensive. It doesn't add value to your project. It doesn't add as much value as automated testing. There is a place for it. So we use a combination of testing and as I was mentioning like on this evolution, we keep adding steps. So we started several years ago using the hat framework for testing. We're also using the robot framework for testing now. Those are behavioral testing. So I'm able to click on different pages, go to those. Visual regression is something that we've added and those tests need to be available. Like I need to know before it's Wednesday and I have a push for the client on Thursday if the build is succeeding or not. We're working on a couple of weeks sprints as a project manager, as a developer. Like it really doesn't help me to go two weeks, think everything's great and not. So you need to have those tests really quickly available. Bahat is, let me just go through this. There's a Drupal library. It comes with many of your already constructed tests for logins, basic Drupal navigation are already built there. There's a working group in Bahat that's actively maintained. People are passionate about it. It's one of the reasons we developed it for projects that we are developing new. Bahat is kind of our tool of choice for building. And behavioral testing. Bahat is, the language is Gherkin so you can see just at the top it says, you know, this is a feature in order to do this. As a user I need to do this thing. You put your assertions in there. It's a plain English language. You have very, you know, this is easy to read. This is available from inside of your Jenkins console and it just reads that out.  Often when we talk about investing in automated testing and writing the test scripts and writing test cases when we build projects, we sometimes get questions about whether it's worth it. Is it worth on my project? Is it worth to invest that time up front to do that? And looking back on what we've done, unless you're going to build it once and one day and then never touch the site again, ever, the answer is yes, it's worth it. Good point. This is the Jenkins dashboard. If you're using Travis or Circle, it's going to be different, but you're going to have some of these elements. You're gonna have the console output. You're gonna be able to see, you know, your source control is tied into this. Your source control gives you the commit. We can see what's there. And in this case, we're building a single, a single commit is building. So you're very granular. Really important that you're doing these builds frequently and that they are granular.  If you have that build test early, then you're able to spot that. So test availability, we actually build, Bahat will generate an HTML output of how did your test run? That actually gives you a report. We link that into our hip chat room and that gives you the ability just to immediately see that the test ran, click on it, see where, where did that happen? I'm showing failures because failures are really your important, that's what you're wanting to catch. I know as developers, we all wanna lay down perfect code. It just doesn't happen that way. So what we need to know is we need to have that feedback and we need to have it often. This is part of that same Bahat report that we saw earlier, but this gives the individual scenarios. It tells you how many of them passed, how many failed, how long it takes to run. It's great. So there's another piece of this. So talking about layers of testing is we also have code sniffer connected to the project and that checks for Drupal coding standards. Code that is written well, code that is easy to read has less bugs. If you've read code complete or rapid development in any of those books and you've worked like it's just easier to debug code that's written well. So automatically it will come through, it will check your project for just layout and having worked with a lot of projects that come in, we see different kinds of coding, we see stuff that's just ran together, it's hard to spot. Having some way to know what state that code in is good and it keeps us all honest as developers when you're committing that you go like, oh, I failed there. We also, so Andy also talked about we have projects we didn't write. Those projects don't come over with the hat test. We may not be familiar with that. So we have a dedicated QA team that QA team uses robot framework. It's a project that's available. There's a blog on our site about how to use it, how to install it. It has a graphical interface. You can go in on the front and build tests. So it's very suited for QA team to run and go through and do a behavioral test to run on the project. On projects that we're supporting, if we do additional work, we'll build those in this test suite. It gives us a way to give code coverage on those. It's not necessarily dependent on us having done the development, but it gives us a way to check those. It's just an additional layer. So we also have manual code review. I think this is an additional testing piece that's really important is not only have I written the test for it, but someone else looks at it. Did you understand what it's supposed to do? Hopefully you've written the test beforehand and that test has been written and looked at. For our entire company, we use GitHub. We use GitHub for all projects. So if you're on BitBucket and we have to work with you, we get to work with you. We get to work with you. We're going to develop in GitHub and we're going to do a commit to BitBucket because the way our process works is everyone's projects, everyone's code, anyone can go look at anyone else's code. It's expected, demanded, encouraged that you look at other people's projects. One of the very early projects I led, we had an issue where in a group, there was some coding issues and just because there wasn't eyes from the outside, it's real easy to be inside of a project and not see what you need. So we added this code review piece manually and that's shared with the entire company where people can see what's going on there. If I clicked into these, I would also see comments inside of GitHub that the developers are making. This will give me, as a project manager or an account manager, it gives me the ability to see what's going on there. The next layer we've added is we're using a tool that we've written internally using WebKit and Phantom.js. Those are really great tools. So especially for sites that are very large or complex. As I mentioned, humans are not great about, it's just terrible to have a list of 100, 200 URLs, you've got to click through them on production and you've got to click through on staging and see did anything change there. So what this tool allows us to do is it allows us to feed the sitemap XML from your Drupal site in, select the pages we're gonna test. It will test it before and after so it uses a reference copy and what it does is it just literally does a full page screen capture and then does a diff of that page and highlights it.  It also has parameters where we can test for different viewport layouts. So we're not emulating mobile but we are able to pick the mobile viewports for tablet and for mobile and test all those and that's done automated. It's been a great time saver on our QA team. It's actually created a lot of open time for that team to take on some new initiatives. But just, you know, and it delivers more value for the clients and you can get that report. You know how the site looks when you're completed without having to wait for it. You have to wait for it a little bit. So next steps, we are working on some internal initiatives for accessibility testing. Is that offering, is automating it? If you've worked with accessibility testing, you know that automated tools do not catch everything. However, what we're looking to do is something very similar to the visual regression test that we can run a tool, get a report afterwards and see where the project is. So that's the next one. Additionally, monitoring. So why is monitoring good?  So as a standard faucet of what we're doing is we install monitoring on all of our dev servers so that we can see, we set that up, we'll put warnings in there in New Relic. Even the free version of New Relic will allow you to set alarms for CPU usage, database usage and let you know when it's over a certain threshold and that's helped us catch a lot of issues. Deploying artifacts. So I'm borrowing also from Michelle Creche's. I see that Acquia has also adopted this in some of their new pipelines and that is deploying artifacts. So with all of those different server environments that we're deploying to, what we found is that if we try to deploy into those environments and we're deploying all the tools, you're deploying Bahat, you're deploying Composer, you're deploying Gulp, you're deploying SAS, that's a whole stack of dependencies on the server that you really don't have to have and it limits where you can go. Sometimes you don't even have the ability to go into the client server and see those things. So we're working with, if we're working with Bitbucket or we're working with Acquia or Pantheon, we're connecting to their get, it allows us just to deploy only the Drupal. Then I only need the Drupal things to deploy. I need all of my updates to be in code so I need to be using configuration management or features if you're in Drupal 7 and we just deploy the Drupal. It's a little bit of learning to get that and it does divorce some of the code history but we found this to be a way to allow us to work over that multitude of environments and just deploy only the Drupal. I've compiled a list of resources that we use internally. These are all very good. It will take you a while to read through these. Don't think that you need to go use all of the resources. Today what I recommend is commit to doing CI, get started with it, start small and then learn those next steps. All of these books have been referenced so those are things that we use.  Wrap up. So last week we're heading out to DrupalCon and we're kind of polishing our presentation. I stopped by Melissa's desk. This is Melissa. You can see she's not miserable like we talked about her previous experience. She's happy. Said, Melissa, why are you so happy? So I had five different deployments this week every single day, different clients, different environments. Everything went well, everything was great. So it can happen. If I encourage you to follow some of those practices, we are asked to display the Friday sprints and please evaluate us. As I mentioned, we are trying to make it easy for you to follow us on Twitter. I've also posted these slides at the bottom of the session description and we'll open it up for questions. Thank you. Questions? I have one. Yep. So sometimes, and you mentioned this at the start, that you have these kind of like less than ideal scenarios. One of the problems I work for an agency, one of the problems that we have is some of our production servers for some of our clients are behind VPNs. And the current situation is we end up having to manually deploy code. And some of these VPNs are kind of like you have to authenticate with Google authentication, things like that. Wondering whether you have any experience or potential solutions for things like that. So the question is, I have production servers which are behind VPNs and how do you deploy where you have very little access to those environments? Did I get that right? Yes. Johnny? We have that exact experience. I think we have to go through a Cisco client for one of our clients employed through the VPN. And here we adopt a strategy of just the best we can. We replicate their entire environment, do a deployment there ahead of time. Then through the VPN, we have a set of scripts on the other side that run to deploy so that we can automate the deployment on the other side as much as we can. But because of the way the authentication is built, there's no way to connect our CI server so that it can reach into their network and do the things that we need to do. It's a wicked problem. I wish there was a better solution if you have it. I'd love to talk to you, but I have had to do deployments before where I cannot touch the other environment at all. And we had to have a go-to meeting share and have the client run the deployment from the other side. It's horrible. Hey, so you discussed a lot of the tools that go into doing continuous deployments. Anything from local to the server and actual actually hosting. Can you give a quick rundown of what a typical from feature to actually needs to get deployed, like kind of a quick rundown of what that process actually looks like? So the question is, I think is, what is the workflow from I've created a feature and tool like this? There's a task that needs to get to production on a Monday. So, take it up the feature in Jira, the developer does the work, writes the test that goes with that work, commits that to a development branch. Our development servers are built every time there is a commit. So those are being built continuously so that we can see what's going on. Most of our projects are built and one of the things I'm looking for is clients that are going to be, we're gonna be able to work with and deploy continuously in production. We don't have that yet. That takes a certain level of maturity. So what we will do, we will tag a release and when a release is tagged, our staging server will see that there is a tag, go out and build that onto the staging so that we have, it'll pull the production database into staging, build there and that's when we can run regression on it and then the production process is a manual piece from Jenkins is that we can deploy to production where we have access but you have to manually select, give it the branch that you're going to deploy. Gotcha. Most people are pretty rightfully so afraid of when do we schedule and do production. Usually there's some timing about how do we take backups, make sure that we're not going to make a mess of things and time that when there's testing available. Okay, thanks. I have a question regarding that we had, you shown in the one slide where you were showing like how many test cases has been executed, how many passed. Like is there any way through the, we can basically get a feeling how much we are covering through the BHAD? For example, like we have a site that might be having maybe 15 to 50 pages. Okay, how much and maybe 15 functionalities. So is there any way like we can say, okay, my BHAD is covering this many functionalities or that much, just looking at them or we are just relying on the tester to write the BHAD. Because here somebody can write the five test cases also, somebody can write the 50 test cases also. We're not using that. I think there are some other folks that I've talked to that have used for code coverage. We really look for, these are typically sites that we're building. So we know what the use cases are when we're starting. So we cover all of those use cases and then as we find places. But I don't have something to run and say, you know, you've covered 80% of the code. Okay. And how do you manage the configuration for the different environments? Like for Dev, like we have some different settings for production, we have different settings. Some are there in the database, some are there in the code. Like how do we manage them? Because like in my case, like we are really struggling. Some there, sometimes we have credential in the database. Sometimes it's there in the code, which is exposed, we don't want to do that. But at the same time, we want to make sure that we should not copy the production configuration on the stage environment, something like that. So the question is, how do you manage deploying code to different environments? And I think this is around the question of maybe in development, I wanna have develop enabled and I wanna hook up to the authorize.net test gateway, we use a environment variable to pass which environment we're building for that will look into a manifest and tell us the settings that need to be set for module configurations and pass that as a separate script. And where are you managing like those config, where are you storing like, whether it's a part of your configuration file, setting.php file or like you're just keeping somewhere on the production so that nobody should be having access to it. Well, it never goes to production because we're using the two repository status. So in our actual build, we have the Drupal is located in a folder below the project and above the project is all of the configuration files and tests that run. So in our GitHub repository, all of those are stored in code in a XML file and then we read it back in. Okay, it means like the part of your code which is there in the GitHub. Yeah. Yeah, okay. And is it encrypted or is just? No. Well, if it is, depends on what information it is. So we'll use a secret key store if it has to do with payment data. Most of the time those are internal to Promet. So we only have access, you know, only Promet and ploys have access to the repository. So we assume that that's a safe environment and we also have, we use Ansible for configuring our servers. So if we do have a change in personnel or we need to move or add people from the team, we can organization wide make those changes on access. Okay, thank you. Well, quick one.  Are there no kind of existing CI tools out there for visual regression testing that you feel work? There are some good tools out there. We used Apple tools. We've used some of the others. We want to have our vision for that tool is to have a dashboard where we can see the entire history of the project and we wanted something that we could control at a lower level so that we could see what did it look like last month? What did it look like last week? What did it look like each build? And when we looked at that set of feature stacks, we didn't see anything that was currently existing. The script is actually pretty simple for what it does. It's just using a web driver, grabbing that screenshot and doing that. And it worked well for us. It doesn't select region. So it's like say sometimes you'll get a slideshow that will fail because it has a different image on it. But it's really great where you have the kind of topography we do where you have many, many projects. You may have a project you come in and you do one thing on just to see, pass, fail, what happened. Are you gonna open source that? Is that great? I will share that or tweet that. I'll have Molly tweet that. But yes, we built on someone else's work and if I could have found the URL, I would have put it here. So thanks. All right, thanks everyone. Thanks.


So here is the problem and the way the program has been written for this. So this is the sample answer that a colleague of mine, Feroza Aibara has prepared. I'll be putting up this on the moodle soon. But I wanted before putting it up to go through this thinking process. We appreciate that this thinking process is important. If you only look at the final answer, you will understand that the answer is correct. But will you be able to create an answer? That is why this thinking process is important. So let us look at what it is doing. Now we are saying that at first the string is accepted from the user. Program requires to find the number of occurrence of a particular alphabet in the string. The character ch is accepted from the user. The first if condition checks whether the character entered by the user was an alphabet or not. Please note this program is not written during examination constraint. It is written later on. That means when you write it for your lab or when you write it at your home, you will think of additional things. For example, you are looking for a character and some sentence is given. But instead of an alphabet, somebody gives you less than sign and says please check whether it is there in the sentence. Now in any English sentence, will you find a less than sign? You will not find. So what she is doing is she is checking first whether the given character is alphabet or not. If it is not alphabet, she says I will tell you that there is no alphabet given. So I can't look for it. That is her style of programming which is okay. Now then she goes and argues if yes, then the uppercase alphabets have ASCII value from 65 to 90 and lowercase alphabets have ASCII values from 97 to 122. Now please note that she is writing this program in a comfort of her room or in the lab. You have access to ASCII code. So she is able to get that ASCII code. This is what you are supposed to do when you write programs for your project or when you write programs for your labs because you have access to other information. If it was an open book examination, I would have expected you to open the book, read the ASCII code, find out the difference and include it. If it is not an open book, then I will expect that you will make some assumption like what I said, any assumption. But as long as you are clear in your mind or I am clear as an evaluator that you have understood that small and capital letter would be different. It is good enough. But in an examination you cannot run the program. That's the problem. We are discussing here how will you answer the problem in an exam. What you are saying is that in a lab, even if I don't have ASCII table, I can actually run the program, ask it to print an integer value. Let's say for one small letter, one capital letter and I can find that out. Yes, that is correct. That is absolutely correct. So that is what if ASCII table is not given, that's what you will do. In fact, he is suggesting that you can actually write a test program and get these ASCII values. And that is the approach you will have to take in the lab or while doing the project when you are doing something more complex. Why ASCII code? You should not do it because ASCII code is such a standard thing that it is available and accessible everywhere. In fact, in less time than what you will take to write this test program on the same computer you can go to internet and ask for ASCII code table. We will get the entire code table. We could calculate the error and integer B and over there only we could calculate the error. How will you calculate that? By, I mean you can store it say one as A and one as capital A and then take the ASCII... Difference, correct. So in fact what he is saying is that I need not do all of this. I can actually calculate the correct difference between two values and get whether the calculated value is correct representation or not. He is complicating the answer but he is very right. Let me spend some time in telling you what exactly he is trying to say then we will come back and look at this answer. So let me say what he is trying to suggest. He is figured out that I do not know whether small A to Z and capital A to Z how they are different, I do not know. So I will start an experiment. I will start an experiment. This experiment says we do not know what small letter capital letter is. So you see what he has done is in a very small time he has thought of another examination problem which he says we should solve as a part of this question only. We are trying to attempt to do that. Nothing is given. How will I discover ASCII code, table and how will I find this difference is the issue. So let me define what am I trying to do. I am saying that I will declare four variables small A, small Z, capital A, capital Z and I will declare ranges small begin, small end, capital begin, capital A. I will now say small begin. Small letters begin with what? Character small A. So I will simply say small begin is from A. Where does small end ends? Capital A begins where? Sorry capital begin and capital end where? Agreed? So whatever is the ASCII code it will come and sit in these integer variables. Now I know the range of integer variables and I also know the difference. The difference is difference between any corresponding characters. So if I say now D is equal to SB minus CB and I also know that what is the range of small and big characters. Now D is SB minus CB that is small beginning and capital beginning or AC minus C. It does not matter. It is the same. Now given a character here is the question given CH find CH2. Meaning if given CH is small P find capital P. And if given CH is let us say capital T find small T. That is what we want to do. CH is given as something small. Find what is the capital? CH is given as something big. Find what is the small words? What can I do? I will find out first whether the CH is in small range or big range. If CH is in small range then the CH2 should be the capital thing difference added. If CH is in big range CH2 is in the small range reverse. So he has given you a excellent logic or excellent approach of even if ASCII table is not known to correctly solve the problem. Let us now look at the solution. So it is saying using the ASCII values it is detected whether the user entered upper or lower case alphabet. Thereafter the upper case is converted to lower case by adding integer value 32 to the ASCII value of the character and is stored in CH2 or vice versa. Now a while loop then reads the string character by character and the value is checked with CH and CH2. If the character is found the variable count is incremented and finally the count is displayed. So let us look at the way the solution is made here. These are the variables used in the program. So I have STR100 which is the string for taking input. CH stores the character to be searched. CH2 stores the lower or upper case character. I is a counter variable. I had used K in that rough draft which is okay. Count stores the count of characters CH or CH2 in this string. So let us look at the program now. Include IO stream. Include STDIO. This is it should be what? Not STDIO.H. In our case what do we say? C A STDIO. Anyway. Int main. I declare these two characters. Int i 0 count is 0. C out enter a string. Get a string. It will get you a string. Enter the alphabet that is to be searched. C in CH. So I got everything. Now see what she is doing. She is saying if CH is greater than equal to 65 and CH is less than 90. Or CH is greater than equal to 97 and CH is less than 122. She is checking whether the character is alphabet. If the character is not alphabet she will not search. Remember I mentioned this. If the given character is not alphabet I don't search. If it is a character then she comes down. Now she checks what is the range. If this is the range the character is uppercase alphabet so CH2 is CH plus 32. If the range is other one else CH2 is CH minus 32. So exactly what you are saying she is doing except that she knows now because she has access to ASCII table that the values are different exactly by 32 and what is the range of small case and what is the range of uppercase. In your case if you really want to write the program and find that out you will have to do that work which I said. Find out small a small z capital A capital Z you get the range and the same range you can check here. So instead of 65 to 90 you will check from AC to SB to AC and CB to C capital beginning to capital N small beginning to small a and appropriately adjust the D what you want. In any case you have got now the character here and the search is now very simple. Having got this CH you are saying she is not even finding out the string length although that would have been easier. We had used a loop for I equal to 0 to N minus 1. What she is doing is she is doing a loop while the ith element of string is not backslash 0 which is end of the string anyway. So she is explicitly checking for that and she says search till end of the string what I have to search if it is not backslash 0 then I have to find whether the ith character is either CH or it is CH too. If the character is found I increment the count. Otherwise I can complete this if statement but because it is while the I will not be automatically incremented so I am incrementing it here. Next character, the comment is not correct. I am not reading next character. I am comparing next character. So I compare next character and go back and do that. When I come out the character CH has appeared count times in my program. There is an else. Why there is an else? She started with an if. If the given character is not an alphabet then if the given character is an alphabet do all of this. Otherwise she says the character entered is not an alphabet. Now some of you would have written the program if you were to do the same check you would have said if the given character is not an alphabet give a message and return minus 1 or return 1. End the program. And then you could have written the rest of the problem. You got how this particular problem is solved? You can what he is suggesting let me elaborate. What he is saying is that suppose the given character is not present there at all then this program will produce an output given alphabet occurs 0 times in the sentence. Logically it is correct but that is not how you answer the English question. How many times character B appears in the sentence? Will you say it appears 0 times? Generally say it does not occur at all. So what he is saying is he would like to put an if statement. If count is greater than 0 then you say it appears so many times. Else you say given character does not appear at all. That is a better way of doing things. Have you done it like that? Or you did not get your answers here? So how many marks do you expect? You expect full marks? Somewhere else you might have made a mistake. You don't know. But you have understood now how this problem is to be solved? Let us go to the next problem. Question 5. So what does the question 5 say? Let us read that question. A value of x is given such that x is greater than 1. We need to find the sum of n terms of the following series where value of n is given. So our thinking starts now. What do we write? Value of x is given such that x is greater than 1. So let me write given x is greater than 1. Then I have to find the sum of n terms of the following series where n is also given. Write a program to read x and n. Verify that x is within given limits and find the desired sum. Suppose without reading any further I write draft. My draft program int x, n. I don't know. At this stage I do not know. It just says x should be greater than n. But it does not explicitly say x can be 2.5 or x can be 3.7. So I may make that mistake. I may assume this. How? When I continue to think, my correction will come automatically. It says find the desired sum. The program should also print the difference of last two terms added. Now that's an additional point. If I have to add n terms, then the last term, last two terms will be what? nth term and n minus 1th term. Now I have to find out, find sum of n terms, find tn minus tn minus 1. Mathematically this is what it is. The difference between nth term and n minus 1th term I have to find out. Now I read the series.  This is the series. I am writing it deliberately in my mathematical form which I know. But now do you realize that if I have to calculate 1 upon x, and x is greater than 1, then 1 upon x will be fractional. It means that x also may be fractional. So I will correct this and I will say no, not this. But int n is alright, but I will say float x. Now I have to calculate sum, so I will write sum. This is my style of writing programs. While drafting, I write int and float, in float care in fact. And whenever I come across a variable, I put that variable there and leave it there. If another variable I require, I will put a comma and put it. And at the end I will put a semicolon. So I don't miss any variables in the declaring. So I have said int n, I have not put a semicolon yet. If I require something else I will do that. I know that I require sum, I know that I require x. Now my formula calculation is not going to be very difficult. Because if I look at the sum, I have to calculate a term and I have to add it to sum. But the term depends upon the previous term. So I need previous term and next term or previous term and current term. So I need two variables. I will call it old term and new term. And I know the formula, new term is equal to old term by what? You look at the formula that is given, the series. Old term by x, old term into old term. He is saying n term is equal to old term. He is saying by looking at the fourth term. Fourth term is 1 upon x square. The second term is 1 upon, third term is 1 upon x square. Fourth term is 1 upon x raise to 4. x raise to 4 is 1 upon x square plus into 1 upon x square. Therefore he is saying old term into old term. The old term is 1. The next term is 1 by x. So the first formula applies. Here is the other alternate interpretations. The other internet interpretation is that one, there is no unique answer to the next term in this given series. I can actually come across, come out with different formulation for the next term which will fit this present series. As it is you find that these two equations which you have given do not fit these. If you have to take one as the first term, one by x as the second term, one by x square as the third term and one by x raise to 4 as the fourth term, what is the fifth term? No, so what is the nth term? Here is a possible interpretation in a programming course. If this was a course in maths and in series, you would be expected to work out what is the nth term of the series and you would have to think mathematically. In a programming question paper, particularly when the question has only 3 or 4 or 5 marks, would it be expected that you break your brains on finding out what is the nth term? Maybe yes, maybe not, you do not know. You have classified this as a simple problem. You have allocated some 8, 10 minutes to solve this problem. Is it worthwhile for you to spend 5 minutes in thinking what should be the right term?  Look, if I do not get the correct nth term mathematically, I may lose some marks. But let me make some assumptions here. Let me make some assumptions here and write that assumption. I believe as a student of programming that as long as my solution is correct as per that assumption, I should get marks for programming. The fact is that if I can figure out what the correct nth term is, then I will still be implementing an iteration. I will be still calculating nth term from previous term and I will be finding out the sum. That logic is correct. So my inability to find the nth term, I may lose maybe half mark or one mark, but for my program I will get marks. Now I have to decide whether I should struggle mathematically to find the correct nth term which will satisfy all these terms or I should spend time in programming. My logic would be that I know there is some confusion. I will take some assumption as long as I state it. Suppose I state it like this. As long as I state it and then implement it, it is correct. But if I do not write this assumption, then whatever you write in your program is wrong because I do not know what you are assuming. Do you understand the importance of comments? This is one question in which the comment is mandatory. Without that comment, people will not understand what you are trying to do. Do you agree? If you do not write a comment, you have something in mind and you implement it. Now whatever you write, whether you have implemented as per your own assumption or not I cannot check. Either your writing should be such that absolutely correct nth term is calculated which is not very easy. We have spent some time. We have not been able to come up with that. Either we do that or we make an assumption, write that assumption. But once you write an assumption, let me say this is my assumption. Now what I have to do now if this is my assumption? What is the program simply? Yes, he is suggesting define an array and define a fault loop, calculate each term, store it in every array element and once n is over, then you take the nth term and the n minus 1th term find the difference and otherwise you sum all of them. But here is a point. Then I have to sum an array and I require only two terms to find the difference. Is an array justified? I cannot keep circling old term, new term, old term, new term and get the final sum. Every time I calculate the term, I add it to the sum. So let me write both the versions. Let us write one version that he is suggesting, one version that I am suggesting. But let us see how both of them can be written in a reasonable time very quickly once this thinking is clear. So what is our thinking? n term is old term by x. That is our thinking. With this assumption, we write as per these two approaches. First we write his approach. I do not know how many terms will be there, n may be 50, 100, anything. Again I will have to write here an assumption. N is less than 1000. N is the number of terms. I am going to set up an iteration. So I will need an iteration variable. Let us say i. I want to find some. So I will find out some value of some. To begin with, I need to set up at least the first term, initial term. I will call it t. Now, to save time, I am not writing c out, etc., etc. I am just reading these two things. Is that okay? I take the first term and assign it to si and I divide t by t by x so that I get the next term. But I have to add this t to the sum. So I will say and I have to find out the difference d.  Is that okay? 0 to n minus 1 are the n terms. My nth term is in s n minus 1. n minus 1 that term is s n minus 2. I will have this here. So I have calculated it correctly. Let me write a program in a slightly different fashion because what I notice here is that the array s is not paying any big role. In fact, even if I remove si equal to t statement, my sum will still be correctly calculated. The only thing I seem to require that array is to get the nth element and n minus 1th element. Otherwise I don't require it. If I can capture an old term and current term, old term and new term or old t and t and keep calculating these and whatever are the last two values, I find the difference between t and old t. I should be okay with it. With that approach, if I write the program, I will say here again int n comma i float x sum t old t and d for difference. I will read c in x and n. I will start with sum is equal to 0. I will start with old t equal to 1. That's the first term of the series. Now I will say for i is equal to, note the way I am thinking. I don't have to handle array elements. So I don't have to run my index from 0 to something which is artificial. I have to count n. So I will say 1, 2, 3, 4, 5, 6, 7, 8, 9, up to and including n. So my loop says for i equal to 1, 2 i equal to less than equal to n. This same as for i equal to 0 and i less than n. Doesn't matter. First time when I come in, i is equal to 1. So what should I add to my sum? The first term which is old t. So I will say sum is equal to sum plus old t. Now I have to prepare for the next iteration. The next iteration will have a new term which is what? I will have to calculate t is equal to, because we have said that new term is equal to old term by x. Our assumption, if somebody had said x square, I would have said x square. If you had a more complicated phenomena for finding out the next term, suppose like Fibonacci series or Hemchandra series, it depended on two previous terms. I would have defined old term, old old term. If it depended on 10 terms, I would have defined 10 terms. I would have got that. But all that I do now here is that's it. My formula is done. Do you agree that when I come out, the sum would have correctly calculated for n terms? When nth term is added, what will be the value of t? Suppose only one term was to be added. Then sum would have become one and t would have become one upon x. When I go back, I will become two and I will come out. Suppose five terms were to be added. You will find that the terms are added one plus one by x, plus one by x square, plus one by x cube, plus one by x four, whatever. Here by the way, my assumption means that the question is wrongly printed. Somebody has missed out one upon x cube. That is what my assumption means. So I may want to write that assumption in details, that somebody has missed that one upon x cube. I am assuming that term is there, whatever. Anyway, but here I would like to suggest that I will end up calculating one extra term in the t. The term which is calculated in t will not get added because my i equal to n will be reached first. Imagine when i is equal to n. What will happen when i is equal to n? When i is equal to n, I will come in here. I will add old term to this. That old term is actually n-th term. But now t is equal to old t by x. I will calculate n plus one-th term in t. And when I come out here, if I find the difference d as equal to t minus old t, it will not be correct. It will be the difference between n plus one-th term and n-th term. Not n-th term and n minus one-th. So what could I do? So there are multiple ways of solving it. He is suggesting that you write an if statement here that if i is equal to n, then before calculating n minus one, you calculate the diff at the end. Another way is saying that you don't calculate t equal to old t here, but you calculate, you start with i equal to two. And first calculate this t and then add it to some. That means in every iteration, you calculate the n-th term. There is another problem here. I am calculating this t here, but I am calculating it from same old t. Old t is not changing. Originally old t was one. So you know what this will do? t is equal to one by x. Then again t is equal to one by x. So it doesn't matter how many times I add. I am only adding one by x plus one by x plus one by x plus one by x. If I have to add n terms like this, I don't require a program. Sigma one by x i equal to one to n is n by x. So I have to modify that old term. I am now therefore, you see, this is what will happen when I mentally execute my program and say this is how the program is going to run. So I will write it once again. Now I will say okay, I have understood what is happening. A, I am going for the next term n-th, n plus one. I don't like that. So let me readjust my formulation. I will say let us see if this logic works. Tell me whether this logic works. I start with sum equal to zero, whole t equal to one. Then I am saying sum is equal to whole t plus sum. What does that mean? I have already added the first term. When I do that, my sum is equal to one already. So I have already added first term. Now I have to keep adding second term, third term, fourth term like that and keep calculating second term, fourth term, fifth term like that. So see what I am doing. I am saying i is equal to two. I first calculate t. t is equal to whole t divided by x. So that is correct. Whole t was one. It will be one upon x. Then next time it will be one upon x square, one upon x cube. I add that. And now I set whole t equal to t. So when i is equal to two, at that time, t will become one upon x and whole t will become what? One upon x at the end. Is that correct? What will happen when I have reached nth term? I will get the nth term calculated as t. It will be added. But whole t will become t. This is... See, please remember, we all thought this was a simple problem. We have allocated how much time for this originally. I am now coming back to examination strategy. We had allocated some ten minutes for this. We have already tried three different tricks. We seem to get the sum correctly, but we are not getting the difference correctly. What he is saying is that, look, instead of getting into all this jamella, I want nth term and n minus one. I will explicitly say if i is equal to n minus one, then some value p1 is equal to this term. If i is equal to n, p2 is equal to this term. And now I will come out and say p2 minus p1 is your difference. You can do that in order to solve that problem. But I will just leave a thought to you. If instead of this, I did the following. If instead of this, I did the following. I start with some t initially. I first preserve it as whole t and then I calculate the new t for this iteration. So if I start with first term, then I preserve that first term as whole t, calculate second term. Next time when I come, I will preserve second term as whole t, calculate the third term. This will work provided I had set the initial value for that term and not for the whole term. All that I need to do is, instead of saying whole t, I will remove whole, I will say t equal to one and I will say sum is equal to t plus. See if I did this, initially sum is zero, term is one and sum is equal to what? t plus sum. That is first term added. Now for t equal to 2 to n, I am doing the following. First time preserving t as whole t. Remember t was one. So when I is two, I have t as first term. I preserve it in whole term. Now I calculate the new term as old t by x, add it. So now I got t and old t as second term and first term. When I go back, I will preserve the last calculated t as whole t and again calculate the new term for third iteration. So at the end, when I come out here and if I simply say d is equal to t minus old t, I would have the correct result. This is where you need to practice writing solutions to such problems at home for different series, different terms, how many terms you have to add, what difference to calculate, et cetera, et cetera. Run these programs on your machine once in the lab and be sure, ah, if I use this logic, it means this. If I use this logic, it means this. And that is the advantage of an open notes exam. If you have written such program and not only the programs you have print out but you have written comments in your notebook that if this has to be the calculation, this is the logic. If this has to be the calculation, this is the logic. Then in an exam time, you will not spend too much time, you know exactly what it is. In fact, it will be in your mind. Once you have written it down somewhere, once you have tried it, you will never forget it. Okay. So do you agree that this kind of logic will work? But more important thing, if I put a semicolon, the iteration will terminate there itself. You don't have to because when you say i is equal to 2, i less than equal to n, that i less than equal to n will terminate the iteration. Remember the condition is always checked at the beginning of a for loop. So initially itself, if i is not less than or equal to n, if n is 1, the iteration will terminate without doing anything at all. That is guaranteed by the for loop. So I don't have to test it. Okay. So this is one way of solving. Let us very quickly look at, so this is the problem. Let us look at the sample solution. She has solved the problem that you are mentioning by assuming n is greater than 3. And by the way, that is not an illogical assumption because anybody who was wanting to add only one term of the series would not have come to a great programmer like you to write a program. Okay. So this is a reasonable assumption. However, if you make an assumption, you should test it. Anyway. So here she has flowtext, sum, term, term old and difference in k,n, give values of x and n and n. She is reading x and n here. She is setting term old as 1. Sum as equal to term old. And she is calculating new term as 1 upon x square. According to me, she should have written here a comment. It is assumed that the successive terms are 1 upon x square times the old term. If you write that assumption in an exam situation, that is correct. Sum is equal to sum plus term. So she is adding two terms independently. First term old and next the new term. So she has now the two consecutive terms as the current term and old term. And now she is running a iteration for k equal to 3, k less than equal to n. All that she does is she takes the current term, makes this old term, calculates the new term and finds out the sum. Almost the same logic that I had indicated what you would do. Capture the old term, keep it there, calculate the new term and add it. And at the end, difference is term old minus term. Value of sum is this. You see, if the logic in your mind is already formulated, so quickly you can write the answer. The answer does not take time. But the thinking could take time. And if this thinking is done a priori before the exam, by solving similar problems and by making sure that in your mind you have clearly the logic how to set the iteration, how to set the initial term, old term, if you have to find the difference what kind of variables you'll use. You'll be able to, you don't need open notes, open book. You'll be able to write the program automatically. That is how it should be. But in an exam, some of you may be spending time, oh, this is the question. Let me see a similar question that I have solved.  You'll lose marks there. Don't do that. First of all, tell me whether the approach that I have suggested makes sense to you. Do you agree that if you experiment like this, now what I suggest is as follows. This is one of the reasons why I have not put up the makeup test solutions on the model. Because if I did that and if I was a student like you, you know what I'll do? I'll wait, shanti se. The model answers come. I'll take a print out. Oh, this question. Okay, this question. So much gaya. And then next exam, nahi samda. Now this happens because I am not applying my mind, I am not experimenting, I am not trying and I am not timing myself. What I would now suggest is these are difficult questions I have already tagged them as difficult questions. They are not very easy questions. So you'll have to think harder. Suppose I say that the remaining four questions, six, seven, eight and nine, you require not 10 minutes, not 15 minutes, not 20 minutes, but 45 minutes per question. It's a one hour per question. Suppose, one hour per question. The point is in the examination either you will attempt or not attempt, but afterwards you will never spend one hour for one question. Because there is no need. Marks to nahi hain kahin bhi. Marks nahi hai toh kaam nahi karne. Abhi yeh mera request hai. Abhi yeh paper hai aap ke pass copy hai. Abhi ek ek ganta ek ek sowal pe lagaye. Spend one hour per question and do what? Do exactly what I said. First read, then think, then write alternatives. And don't write one program. Write two programs. Write three alternate programs or modify some portions. And then finally make a fair copy. And then hand execute that program. Hand execute karun. Find out whether it works or not. You can do all that if you spend one hour per question. You can't do that if you spend 15 minutes. In 15 minutes you can only read an answer and understand it. But you will take one hour to construct it. Here is my request to you. Spend one hour on each of these questions. Each of these questions. And understand the principle. Within this week I will be putting on the moodle not only the answers which Feroza has written but I will be putting up additional explanatory notes saying that if I think like this my solution will work like this. If I think like that my solution will work like that. You will see alternate answers. You may find that what you have thought is a third way. That is perfectly possible. But you have to make sure that the answer is correct.


In today's video, we're opening up a $5,000 Yu-Gi-Oh! collection. What's up, guys? We're back with another epic video. In this video, I will be opening up a collection that I'm actually consigning for a viewer. But before that, we have a giveaway. I'll be giving away these three cards. We have the Gaia, Dark Paladin, and Dark Magician from LOB. All you have to do is like the video, be subscribed to our notifications. Let me know down below your favorite card in this collection. There's a lot of nice ones. Let's get into it. Okay, so inside this box, we have a pretty nice collection that I'm going to be opening up. And I'm going to be selling it for a viewer. So if you guys are interested in any of these cards, they will be for sale. By the time you see the video, some of them may have sold because I usually start selling them before the actual video comes out. But there should be some stuff left. So hit me up if you guys are interested in that. Check out my Instagram. That's where I'll be posting it at Ruxin34. And let's get into it. All right. He actually sent us a little bit of a bonus here. We have a Cocoon of Evolution. That seems to be the only card. I don't think there's an extra card. So Cocoon of Evolution, no Pocainio moth hidden there just making sure. Let's go through. There's only 71 cards here. It's a pretty high-end collection. It's like pretty decent value per card, which is the kind of stuff that I would be willing to consign. So if you guys are interested in consigning more high-end collections like PSA cards or high-value singles, then hit me up. I wouldn't do stuff like really cheap because that's like a ton of work and you make like 12 cents per card or whatever. So if you are interested in consigning, I might do that. It's not something I do a ton, but I am open to possibly doing it. If you have some PSA cards you want to sell, not necessarily PSA, but greater cards you want to sell. So if you guys are interested in that, send me an email to rodneyruckson34 at gmail.com. Instagram would work as well at ruxson34. Let's start going through these cards. There's some really nice stuff here. Let's start off. All of these have these pull tabs. Do you make these into pull tabs? Or did he tape them? He taped all of them. This is going to be fun. Okay, so lightning vortex right up the bat. I'm not going to check out every single card, but I was already looking at this card eyeballing it a little bit while I was talking. That is a really nice looking ultimate rare. Check that out. Wow, lightning vortex. Beautiful, beautiful card. I'm going to have to go through all these cards in like double check conditions and stuff like that before we get to selling them, but very awesome. Lightning vortex is just a great way to start. Okay, ring of destruction. That is an unlimited. No, wait, no, this is a retro pack too. There are actually a couple of these, I think. So we have a second retro pack, and then he had a play set of retro pack, ring of destruction. This is a card I've never actually seen before in person. It's kind of one that I forget is a retro pack secret. It's kind of random that they put a ring of destruction in there, but I guess at the time it was still, was it banned at this point? Or did they erotic? They might have eroded it around then. I'm not sure. Let's read it. Destroy one face of monster flick game. Nope, that seems like the original print. Okay, just want to look at this a little bit closer. Okay, let's just look at one of these. Secret rare looks pretty cool. And you can almost get the secret rare to completely disappear. I didn't know them, not anymore. Blue eye shining dragon or ring of destruction, which do you prefer?  I mean, obviously, I think I know what you guys are going to pick, but that's a really nice looking card as well. Next up, we have another play set. And this is a pretty awesome one. I don't think I've ever actually owned these either, which I don't know, obviously, because they're consigned, but pot of duality, ultimate rare play set. We're talking one, two, three, you can play all of them. You can then activate this and hopefully in Masterful, they'll chain maxi and it'll be perfect. I remember when I first used this in auction series, I didn't know that you couldn't special summon. Kind of the main restriction of the card. Pot of duality, ultimate rare, very beautiful. These cards look absolutely sick. All right, let's get one more look of the play set.  How about that? These look really nice. Any difference between the three prints? I feel like this middle one looks a little different. Maybe you should, no, I think it's just that angle. Next up, we have another play set. It's Chaos Sorcerer. These are from TurboPak 2. We actually, I think pulled a couple. Did we pull a couple of these? I think I pulled one for Kaz actually. I think it's when we pulled one. Yeah, I didn't get to open a lot of TurboPak 2, so I didn't actually pull many myself, or any myself. I did pull one for Kaz though. These are like a goat format staple for a long time. These were the high rarity of Chaos Sorcerer. There's some other good options as well, but I think this is one of the highest rarities. Looks like the play sets have ended. We have an ultimate rare mystical space typhoon. This is kind of a weird high rarity card. It looks pretty cool, but it's a little bit dark, so it's specific to people's taste. Some people don't like this, some people do. I do like it. I think it shines actually pretty well when you hit it in the right light. It's kind of nice dark blue there. Looks pretty beautiful. So the Astral Pak mystical space typhoon. And here we have an ultimate rare sacred phoenix of neptis. This is one of my favorite cards. This card looks so cool. Sacred phoenix ultimate rare from Flaming Eternity. Let's take a closer look at this guy. So I don't think this one's in like great condition, if you guys can tell already, but these things are triple sleeved. Okay. Yeah, the edges are not awesome, but this is still in the sleeve, by the way. It's in the small sleeve, but really beautiful card even in that condition. Very, very nice sacred phoenix of neptis. We're back to the play sets. We have three threatening war. These are champion pack. These are pretty nice as well. Just super rare, but a lot of the champion pack cards that are really expensive are actually just supers, probably because this did not have a foil print for a long time. I think it came out in Flaming Eternity as a common. And then they got this champion pack seven print a couple years later. And this was the one that you wanted to play in your high rarity goat format and stuff like that decks. Then we have another playable card, an ulti terraforming. So this card is still pretty useful to this day. I think you have banded master duel. Did he get banded into TCG? I can't remember. It's definitely a one at wherever it is, even legal. So a very, very cool card, ultimate rare. It's always been pretty expensive because getting field spells is just really, really good for a lot of different decks. So ultimate rare printing, very nice. Then we've got a card that I love to play, the fossil dino patch of cephalus. This card's hilarious in Edison. You flip it up and it destroys all those special summons monsters or you just summon it. They can't even special summon. It's a very annoying card, but it's pretty funny. When you play into like, are you kidding me, you're playing this card? Very nice. It's a couple of them are first dead yet. One's unlimited. Very, very beautiful. It's a secret rare from lighted destruction. So talk about a very rare set. So secret rare, one of the highest rarities in the set. Pretty hard card to come by. So not bad at right there. Oh, this one's bringing back bad memories. Instant fusion. This was, oh, these foreign. Oh, interesting. All right, I didn't realize that. So I'm gonna have to, I'm gonna have to get back to them because I didn't actually realize these were foreign. I don't think at the time. These are a little bit different when it comes to like actual pricing. Obviously, foreign's a little bit harder to move. But also this card brings back bad memories because the Twitch chat made me invest in this card when we knew it was gonna go down the whole time. Even they knew. They made me buy it because I let them decide. They voted ultra rare. They look cool. I'll say that, but it's just a good chance it gets banned. I'm not even sure that's not banned right now. I think it's at one or some, I don't know. And speaking of, okay. I don't know why those, I said speaking of, these are definitely not banned, but enemy controller, very cool first edition ancient sanctuary. I still usable every once in a while on some certain decks. So it's a pretty crazy card from back then. And it's a classic anime card up, down, left, right, Kaiba definitely rocked that card. Then we have the legendary pot of greed, just an unlimited here out of the Duelist Pack Kaiba. First set is pretty crazy. I think it's like 200 bucks. So this one's more like 30, 40, 50, something like that. I think it might even be 50, which is, I mean, that's pretty high for a card that's been banned since the beginning of time. But it's so iconic. It's available in some older formats. So, you know, there's some value there. Back to more champion pack. We have Prohibition, a play set, super rares. I did pull some of these. I'll pull one or two when we open champion pack six or eight, I mean, sorry, not six. This is the one with the Lumina, yeah. Prohibition, it's a pretty good card. It's a pharaoh servant rare originally. So it's a very, very old card. Got that champion pack reprint. And if you do play this card, you want that hollow champion pack version. Back to the goat stuff. We got a couple of suks. So ultimate rare, Sukiyomi's from Astral Pack. Are these foreign as well? I don't remember him marking them foreign. So it doesn't really matter because it's a consignment anyway. So it's not like I bought it or anything, but I just didn't realize these were foreign. So Sukiyomi, it appears to be English because it's the same name.  That is not same magician. So really cool cards. And honestly, the foreign ones kind of have a little bit more pop to them, I think. So I think that's probably why people play those. Then we've got a couple ga ga ga cowboys, little burn at the end of the game. You know, ga ga ga cowboy for game. It's a classic moment. Okay, maybe not a classic moment, but you might remember it happening to you. It might be rough. You know, one of the early XT's monsters, it's actually pretty solid. It's got a couple of good effects. That burn effect can be good. That boost effect can be good. Pretty cool. Another play set. We got Pot of Desires. Another one that we had to invest in in our 1k. This one isn't as bad, but still it's, I think it's limited or it's down to semi-limited or what? It's definitely not semi-limited. It could be limited. Very crazy cards. I don't know why I'm flipping this around, but beautiful. More Pot of Greeds, you know, updates the Pot of Greed because Pot of Greeds is too good. So we had to do that version, even though that could be better than Pot of Greed in certain decks. Then we got, speaking of drawing cards, the upstart goblin. This is a Super Rare from TurboPak. Pretty awesome looking print. I don't know. I think this is the highest rarity in terms of like hollows at all, except for Legendary Collection, Yu-Gi's World is like an Ultra. This is obviously a lot older, so it's a little bit more valuable. We got another playset. We got the scapegoats. These are not the highest rarity because they got Retro Pak 1, so it's hard to beat that, but these are the Ultimate Rare prints. So they are pretty cool. Another one that's kind of dark and a little bit weird, like some people like them, some people don't, but they're pretty nice looking. They're pretty clean, I'll say. I remember pulling some of these, we were opening some of these OTS packs a couple of years ago. Then we have some more Ultimate Rare. It's Monster Ring Incarnation. These are really cool. Rise of Destiny Ultis, the first edition. They're very, very nice. This is a card you don't see that often. Like, it's just a regular Rare and Rise of Destiny, so it's like a Retail Ultimate Rare. And it's really, really nice. It's actually decent in some formats and stuff. So it's actually a crazy card. You just don't really see it that often because those Retail Ultis can be hard to find because a lot of them are garbage. And then like, there's so many different Retail Ultis. It's hard to pull a specific one. Here's a cool one. We got the Power Tool Dragon Ultimate Rare. This is not a first aid, but still really cool. I mean, it's not the ghost either because there's so many different versions.  I love Ultra Rare Synchros. They look awesome. Not as good as Ghosts.  Some of my favorite Rarities. Now we got Thunder King Ryo. Very, very nice. Thunder King Rios. These are beautiful. Thunder King Ryo got expensive for a while because it got like used in a YCS or something. Like it's such an old card, but it got used. And these are some of the highest Rarity. There's like the Ultimate Rare as well. But this version, I don't even know what this stands for. It's like some sort of like magazine or something like that. But the Secret Rare on this version looks incredible. So I'd probably like it better than the Ulti. I'm not going to lie. Hey, look, Ring of Destruction has returned. This is the first at Ultimate Rare. If you've seen Ring of Destruction, we've already seen the Secret. So we'll keep going past those. We got a couple of machine duplications. You're trying to play those Cyber Dragons. Here you go. Ultimate Rare, First Edition from Rise of Destiny. Also, Retail Ultis in Rise of Destiny. There's some crazy Retail Ultis in Rise of Destiny. Then we have a Rygeki Ultra Rare from Retropack 1. So speaking of Retropack 1 in those scapegoats, there's a Rygeki from that. Oh, that's foreign. Okay, foreign. Not as crazy as I was thinking, but still pretty crazy. Retropack English is just nuts. We got Utopia, the Lightning and Ultimate Rare from... This is like one of the newer cards, OTS9 it looks like, so which at this point is like 13 OTSs away. And Ultimate Rare Mystic Swordsman, Unlimited, but nice for the Warrior Deck and Goat Formats. So also pretty beautiful. I have a couple of these myself. Three Trap Dust Shoots. What version is this? Dual Terminal. Interesting, Dual Terminal. So instead of Champion Pack, you have the Dual Terminal versions. These are ones I don't think I've ever actually seen. So probably pretty rare there as well. Then we have the Ultimate Rare First Edition Creator. This man has a lot of Rise of Destiny. He has like all the best cards out of Rise of Destiny. The Creator, Cover Card, very awesome looking card. You'll love to see that guy.  He's not very good, but he is very cool looking. Very collectible. I'll say that. Now we got some more Drawing Ability. We have the Grateful Charity Secret Rare for Legendary Collection in Yu-Gi's World. You'll be shocked at how expensive this is. Like 40 bucks or something, maybe even 50 from Yu-Gi's World First Edition. Some of those First Edition Yu-Gi's World Cards are crazy. Then we got Change of Heart Secret Rare, another Yu-Gi's World Cards. Same thing with this one. I think it's like 30 or 40 bucks. Pretty wild. Then we have Dimension Fusion First Edition from IOC. We pulled one, graded it, and ate. That was awesome. Don't worry, we have two and we have three here. So a play set of those. If you guys want to go crazy, still banned, I believe. So 2004 to now. Pretty long time. I don't think he got banned right away, but later until the seven or something, I got banned. Still several more cards. We've got a Retro Pack 1 Solem Judgment. This one is English, so we got a Super Rare Retro Pack 1 Solem Judgment. Beautiful super. Lot of Princess Solem Judgment now, but this is probably one of the rarest. Now, if you want to link one, you got the Link Spider. Spider, spider. That's a different card that's from Star to Sober Drop. Link Spider, though. Ultimate Rare's OTS7, I believe. I think I remember opening for this. Yeah, OTS7 Link Spiders. Those are really cool. We got a Sun Dragon Inti, and it wouldn't be the same without the Moon Dragon Quilla. Two First Edition Ultimate Rare's. Those are really nice looking cards. I really like the Moon, I think. Sun and Moon, little Pokemon action going there. Then we have a Ghost Rare. I think this is the only Ghost Rare we have. The Odin Father Yaser Unlimited. Very beautiful as well. Gotta love a good Ghost Rare. I mean, it's not a great collection without a Ghost Rare in there somewhere, right? Beautiful, beautiful hollow. Looks awesome. Then we have a Jinzo from Retro Pack 2. We pulled a couple of these in our day. Very nice looking card. The clouds in the background look very menacing with this hollow rare. It looks really, really nice. And finally, we have one more card. We have the Master Collection 2 Black Luster Soldier on the beginning. One of the better looking Black Luster Soldiers, even though it's not that crazy expensive, but this is a really nice Secret Rare card, BLS.  So if you guys enjoyed the video, don't forget to subscribe to the channel. And if you guys are interested in any of these cards, hit me up on Instagram or through my email. And if you want to consign as well, hit me up and we can talk about it and see if it'll work out for both of us. Shout out to Toamfo Show, Dax, or JT Show, Puffins of Doom, Ernesto, Deanna, America Doidster, Supreme Stage 21, CJ, Leo Guine 62, another Thai show, Ian Moosa, Junior Barney, Mimic Gecko, and Robert F. Thank you guys for supporting the channel. And I'll see you guys in the next video. Peace.


Because the new revenue recognition standard allows revenue to only be recorded at the net amount to be realized, we need to learn how to account for the return of goods as well. So let's look at this example. During January, we sold goods on account for $200,000 with a cost of $80,000. No sales discounts were offered. This journal entry is pretty straightforward. We debit accounts receivable and credit sales revenue for the revenue amount of $200,000. We debit costs of goods sold and credit inventory for the cost of $80,000. However, most companies experience returns. In this example, let's assume that approximately 5% of sales are returned. We debit sales revenue and credit refund payable for 5% of revenue, which in this case is $10,000. We also need to record the estimated return of inventory at 5% of cost. So we debit estimated return of inventory and credit costs of goods sold for $4,000, the estimated return of goods. Once the month is over, we can record the actual amount of returns and correct our estimates. In this example, assume that $8,000 of goods were returned. Those goods had a cost of $3,200. So we debit refund payable and credit cash for the $8,000. We debit inventory and credit the estimated return inventory for $3,200.