<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.2.0">Jekyll</generator><link href="https://saltyvagrant.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://saltyvagrant.com/" rel="alternate" type="text/html" /><updated>2022-01-31T12:41:10+00:00</updated><id>https://saltyvagrant.com/feed.xml</id><title type="html">SaltyVagrant</title><subtitle>A site of devops educational material.</subtitle><author><name>Mark Bools</name><email>mark@saltyvagrant.com</email></author><entry><title type="html">Why I won’t work for Google</title><link href="https://saltyvagrant.com/2021/05/01/why-I-wont-work-for-google.html" rel="alternate" type="text/html" title="Why I won’t work for Google" /><published>2021-05-01T00:00:00+01:00</published><updated>2021-05-01T00:00:00+01:00</updated><id>https://saltyvagrant.com/2021/05/01/why-I-wont-work-for-google</id><content type="html" xml:base="https://saltyvagrant.com/2021/05/01/why-I-wont-work-for-google.html">&lt;!--  l. 10  --&gt;
&lt;p class='indent'&gt;&lt;/p&gt;
&lt;div class='abstract'&gt;&lt;span class='ecbx-0900'&gt;TL;DR&lt;/span&gt; &lt;span class='ecrm-0900'&gt;Building a YouTube business is not something I will ever do.&lt;/span&gt; &lt;span class='ecrm-0900'&gt;Here’s why.&lt;/span&gt;
&lt;hr /&gt;&lt;/div&gt;
&lt;!--  more  --&gt;
&lt;!--  l. 18  --&gt;
&lt;p class='indent'&gt;I do have a &lt;a href='https://https://www.youtube.com/channel/UCixF-dbadJ8JpWMoKHP9uRg'&gt;YouTube channel&lt;/a&gt; but it is simply a method of giving away ‘free’ content and making people aware of my own &lt;a href='https://saltyvagrant.com'&gt;web site&lt;/a&gt;. Where Google permits I monetize the ‘free’ content on this channel (Google takes my work and add it’s own adverts regardless, so I make bank where possible).&lt;/p&gt;
&lt;!--  l. 20  --&gt;
&lt;p class='indent'&gt;The problem, as so many have realised in the past, is that any YouTube creator is subject to the indifferent caprice of Google so the idea of using YouTube as a platform to develop a business is risible. So long as you understand this the deal is a good one. Google provide the platform to distribute video content without cost to the creator, the creator reaches a potentially larger audience than they might otherwise.&lt;/p&gt;
&lt;!--  l. 22  --&gt;
&lt;p class='indent'&gt;If, however, you believe that using YouTube to develop a business is a good idea I think you’re in for a bad time. (You might get lucky, but the odds are against you.)&lt;/p&gt;
&lt;!--  l. 24  --&gt;
&lt;p class='indent'&gt;Google cares not a jot about creators. YouTube is a machine for getting adverts in front of eyeballs. Period. This means Google will prioritize any action that preserves or enhances this function. This is why DMCA take downs, copyright strikes, and the like are automated with virtually no way for creators to win (regardless of the merits of their case). You can literally see your business vanish in seconds and unless you are fortunate enough to have access to the right back channels you
are unlikely to ever see it return.&lt;/p&gt;
&lt;!--  l. 26  --&gt;
&lt;p class='indent'&gt;Furthermore, Google’s algorithm optimises for revenue generation so if your content is not feeding this algorithm your content will languish in relative obscurity. This algorithm is responsible for the ‘race to the bottom’ we see on platforms such as YouTube. Sure, there are many excellent channels, but the one’s that attract the most attention from Google are the ones that the algorithm sees as potentially revenue generating. Even large YouTubers have noted the fragility of their
position in this regard.&lt;/p&gt;
&lt;!--  l. 28  --&gt;
&lt;p class='indent'&gt;This is not a Google problem. Blaming Google for this is like blaming a Bear for shitting in the woods. It’s just what they naturally do.&lt;/p&gt;
&lt;!--  l. 30  --&gt;
&lt;p class='indent'&gt;If you focus on building a ‘YouTube business’ then you are working for Google.&lt;/p&gt;</content><author><name>Mark Bools</name><email>mark@saltyvagrant.com</email></author><category term="opinion" /><category term="shorts" /><summary type="html">TL;DR Building a YouTube business is not something I will ever do. Here’s why.</summary></entry><entry><title type="html">It’s easy!</title><link href="https://saltyvagrant.com/2021/04/09/its-easy.html" rel="alternate" type="text/html" title="It’s easy!" /><published>2021-04-09T00:00:00+01:00</published><updated>2021-04-09T00:00:00+01:00</updated><id>https://saltyvagrant.com/2021/04/09/its-easy</id><content type="html" xml:base="https://saltyvagrant.com/2021/04/09/its-easy.html">&lt;!--  l. 5  --&gt;
&lt;p class='noindent'&gt;&lt;/p&gt;
&lt;!--  l. 10  --&gt;
&lt;p class='indent'&gt;&lt;/p&gt;
&lt;div class='abstract'&gt;&lt;span class='ecbx-0900'&gt;TL;DR&lt;/span&gt; &lt;span class='ecrm-0900'&gt;A few thoughts on learning to program and the ‘ease’ of&lt;/span&gt; &lt;span class='ecrm-0900'&gt;prgramming.&lt;/span&gt; &lt;!--  l. 17  --&gt;
&lt;p class='indent'&gt;&lt;span class='ecrm-0900'&gt;Inspired by&lt;/span&gt; &lt;a href='https://dorinlazar.ro/2021-02-programming-is-hard/'&gt;&lt;span class='ecrm-0900'&gt;this&lt;/span&gt;&lt;/a&gt; &lt;span class='ecrm-0900'&gt;article.&lt;/span&gt;&lt;/p&gt;
&lt;hr /&gt;&lt;/div&gt;
&lt;!--  more  --&gt;
&lt;!--  l. 20  --&gt;
&lt;p class='indent'&gt;People who say (and mean) ‘programming is easy’ are generally those in the middle of their career (or their learning curve). To beginners programming is hard because it is new and unfamiliar, they have a sparse pre-existing knowledge structure to hook into. The beginner needs to develop both basic knowledge and the instinct for applying that knowledge. This is hard.&lt;/p&gt;
&lt;!--  l. 22  --&gt;
&lt;p class='indent'&gt;For master programmers programming is hard because they take on hard problems and hard problems tend to require novel thinking and more advanced programming skills.&lt;/p&gt;
&lt;!--  l. 24  --&gt;
&lt;p class='indent'&gt;The journeyman programmer, the programmer who has learned and internalised the basic skills and can apply them consistently begins to believe that programming is easy. Time will disabuse the good journeyman of this conceit. Many programmers do not progress beyond this ‘programming is easy’ naivety. They know ‘enough’ and that is sufficient to earn a living, and that’s fine. They will spend their career essentially ‘solving’ the same problem over and over. A few though will forever be
looking to challenge themselves with new problems requiring improved skills. These few will eventually become master programmers and realise that no matter how much they know there is always more to learn. No matter how easy some elements of programming become for them there are always more elements that remain difficult (until mastered).&lt;/p&gt;
&lt;!--  l. 26  --&gt;
&lt;p class='indent'&gt;My own journey began over 40 years ago, in many respects I am still a journeyman programmer. I learned to program in 1980. I have earned a living programming since 1987. I am still learning. For me some elements of programming are now ‘easy’ but many remain hard (if they weren’t I would have no incentive to continue, what’s the point in doing something easy?)&lt;/p&gt;
&lt;h3 class='sectionHead'&gt;&lt;a id='x1-1000'&gt;&lt;/a&gt;The well intentioned lie, “programming is easy”&lt;/h3&gt;
&lt;p&gt;&lt;a id='x1-1000doc'&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!--  l. 31  --&gt;
&lt;p class='noindent'&gt;I think (hope) that most people saying ‘programming is easy” are trying to encourage people to try their hand at programming. This is a laudable intention but I think it often has the opposite effect, especially on beginners.&lt;/p&gt;
&lt;!--  l. 33  --&gt;
&lt;p class='indent'&gt;If you’re learning something completely new, say (picking something entirely at random) juggling, and someone even slightly proficient tells you ‘it’s easy’ the impact is not encouragement it is demoralising. If it’s easy and I can’t get even this basic skill right I must be incapable of juggling. The truth is that almost any new skill is hard, very hard, when you start learning it. The more you practice the easier it becomes. What’s more once you have developed knowledge of the
principles involved in a new skill you generally find extending your knowledge easier than learning the initial skill. The difference between juggling three balls and four balls is less than acquiring the skill to juggle those first three.&lt;/p&gt;
&lt;!--  l. 35  --&gt;
&lt;p class='indent'&gt;But there comes a point where things become hard again. Sticking with my juggling example, three to four balls is easy enough, four to five is more challenging, five to six is hard, and six to seven is much harder still. Beyond seven and you are into &lt;a href='https://en.wikipedia.org/wiki/Juggling_world_records'&gt;world record&lt;/a&gt; territory. Then there is the challenge of juggling objects of different size and weight. You may have mastered juggling three balls of equal size, then someone
hands you a ping pong ball, an orange, and a pen. Juggling three things just took on a whole new level of difficulty.&lt;/p&gt;
&lt;!--  l. 37  --&gt;
&lt;p class='indent'&gt;Programming (or any other skill) has the same sort of challenges as you progress. First everything is new and it seems impossibly difficult. Sure, some people take to it easier than others. For some it just ‘clicks’ earlier. I was fortunate. I enjoyed the challenge of making a computer do things. I enjoyed taking my early efforts and figuring out how to make them better. Was it easy? Nope. At the start it was frustrating and hard but over time it became easier to see the solution. It
became easier to understand how I had messed up.&lt;/p&gt;
&lt;!--  l. 39  --&gt;
&lt;p class='indent'&gt;Then I discovered assembly code. A whole new way of thinking, a whole new set of limitations. Suddenly what was easy became hard. A few assembly programs later I was confident enough to declare, ‘assembly is easy’. (I especially liked declaring this to school friends who had no idea what assembly code was. Yeah, I was a bit of a jerk when I was 13.)&lt;/p&gt;
&lt;!--  l. 41  --&gt;
&lt;p class='indent'&gt;Then a school friend showed me something they had written and… I felt dumb as a brick again. He’d written some assembler (actually he wrote a program allowing the &lt;a href='https://en.wikipedia.org/wiki/ZX80'&gt;ZX80&lt;/a&gt; to display what was then ‘high resolution’ images—long story for another day). Suffice to say his code was elegant. His solution to something I did not even recognise was a problem until I saw his code was just so far advanced from my own efforts that for a couple of days I
despaired. Then, once I’d figured out his code, I felt empowered. New knowledge, new abilities, and consequently a whole new set of problems and solutions became available. Sure, programming had become hard again but in a good way.&lt;/p&gt;
&lt;!--  l. 43  --&gt;
&lt;p class='indent'&gt;In the intervening decades I’ve experienced this roller-coaster many times, enough to realise that ‘it’s easy’ is seldom accurate. At best one can say, ‘this is easy for me now’. Any time I find myself thinking this I realise I’m not challenging myself enough. If you find yourself declaring ‘programming is easy’ I suggest you try something more challenging. I’ll wager most of you learned Java, C, JavaScript, Python, or PHP. If so, try Lisp or Haskell. Then tell me programming is easy on
your first day. Still too easy, try Prolog. Still too easy? Okay, take any language and write a simple web server. Wait a second! No frameworks. No libraries. No cut-and-paste from the internet. I mean write one from scratch.&lt;/p&gt;
&lt;!--  l. 45  --&gt;
&lt;p class='indent'&gt;Yes, learning correct syntax for a language is ‘easy’. Learning a second functional language once you know one functional language is ‘easy’. But switching to a declarative language when you’ve only ever known functional languages is hard. Considering even ‘simple’ tasks (knocking up a web server in Python is only a dozen lines when you have access to Flask, but that’s not really programming it’s mechanics).&lt;/p&gt;
&lt;!--  l. 47  --&gt;
&lt;p class='indent'&gt;It’s easy to be bad. Another trait I see in people who declare ‘programming is easy’ is that their code sucks (and often is nothing more than cut-and-paste with a bit of glue code around the edges). I’ve seen people claim programming is nothing more than being able to use StackOverflow and Google. These people are either joking or idiots. Being able to find resources is an important skill, but if misused it leads to dependence and shitty code.&lt;/p&gt;
&lt;!--  l. 49  --&gt;
&lt;p class='indent'&gt;It’s easy to do the easy stuff. Another feature of the ‘programming is easy’ crowd is that they seldom tackle difficult problems. Any monkey can knock together a simple web server in Python. You really don’t need much more than a rudimentary level of knowledge or skill. Heck, you &lt;span class='ecti-1000'&gt;can&lt;/span&gt; just cut and paste the code for a Python web server from any of thousands of tutorials. But tackling a novel problem, or even simply scaling up the simple web server you just
made, is a harder proposition. Programming is more than writing code, it’s solving problems.&lt;/p&gt;
&lt;!--  l. 51  --&gt;
&lt;p class='indent'&gt;Tutorials make it worse. By this I mean you can get a false sense of your achievement from a tutorial. It is trivial to follow along with a tutorial and think ‘that was easy, so programming is easy’. Then you tackle your first real-world problem and… programming become hard. Don’t get we wrong, tutorials have their place. I’m just saying they can give a false sense of achievement.&lt;/p&gt;
&lt;!--  l. 53  --&gt;
&lt;p class='indent'&gt;You are not exceptional. (There may be one of you reading this that is, in some limited scope, exceptional but for the rest of us we’re not exceptional.) This is not a bad thing! It is a simple fact of statistics that by definition most people are about average. Some are a little above average some a little below. Ironically those most below average tend to think themselves exceptional— the &lt;a href='https://en.wikipedia.org/wiki/Dunning%E2%80%93Kruger_effect'&gt;Dunning-Kruger effect&lt;/a&gt;.
What is more, even if you are exceptional in one respect you are average in many, many others. Live with it. Embrace it.&lt;/p&gt;
&lt;!--  l. 55  --&gt;
&lt;p class='indent'&gt;Two guys walking in the woods happen upon a bear. The bear starts to chase them and one suddenly stops, opens his backpack and starts changing his boot to his track shoes. “Are you mad!” his friend shouts, “you’ll never outrun the bear even in track shoes”. “Oh, I know,” says the man, “but I only need to outrun you.” It takes a lot of pressure off if you remember to be successful you only need to be slightly better than the next guy.&lt;/p&gt;
&lt;!--  l. 58  --&gt;
&lt;p class='noindent'&gt;&lt;/p&gt;
&lt;h3 class='sectionHead'&gt;&lt;a id='x1-2000'&gt;&lt;/a&gt;The humble-brag, “programming is easy”&lt;/h3&gt;
&lt;p&gt;&lt;a id='x1-2000doc'&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!--  l. 61  --&gt;
&lt;p class='noindent'&gt;There are some people who feel the need to inflate their own ego by putting other down. The statement ‘programming is easy’ is sometimes to put others down. ‘How can you not get this? Programming is &lt;span class='ecti-1000'&gt;so&lt;/span&gt; easy!’ This a malicious form of the humble-brag, statements that, on their face, are modest but are actually intended as a brag.&lt;/p&gt;
&lt;!--  l. 65  --&gt;
&lt;p class='noindent'&gt;&lt;/p&gt;
&lt;h3 class='sectionHead'&gt;&lt;a id='x1-3000'&gt;&lt;/a&gt;Programming is hard&lt;/h3&gt;
&lt;p&gt;&lt;a id='x1-3000doc'&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!--  l. 68  --&gt;
&lt;p class='noindent'&gt;Okay, the mechanics of programming are generally not hard once you grasp the basics. What is hard is the problem solving required in programming. Learning how to translate from the problem, to a potential solution, to writing code to execute that solution, is difficult but gets easier as you build a store of previous solutions and get better at breaking problems down into manageable chunks susceptible to solution.&lt;/p&gt;
&lt;!--  l. 72  --&gt;
&lt;p class='noindent'&gt;&lt;/p&gt;
&lt;h3 class='sectionHead'&gt;&lt;a id='x1-4000'&gt;&lt;/a&gt;Programming is accessible&lt;/h3&gt;
&lt;p&gt;&lt;a id='x1-4000doc'&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!--  l. 75  --&gt;
&lt;p class='noindent'&gt;There is nothing preventing anyone with access to the internet learning to program. Particularly when you remember ‘on the internet no one knows you’re a dog’, in other words no one knows your age, gender, skin colour, sexual orientation, previous education, current occupation, or anything else generally associated with exclusion.&lt;/p&gt;
&lt;!--  l. 77  --&gt;
&lt;p class='indent'&gt;You will need access to a computer, access to the internet, and your own motivation. That’s it.&lt;/p&gt;
&lt;!--  l. 79  --&gt;
&lt;p class='indent'&gt;But don’t I need an expensive computer? No. Sure, there are many situations where having a whiz-bang computer will be beneficial but when you’re starting out just about any computer will be fine. (I learned to program on an 8-bit computer with 1k of memory—and no internet! So I am sure you’ll be fine with any modern computer. Get yourself on e-bay and buy a cheap second hand laptop.) Can’t afford a computer? Go to your local library, many allow free access to the internet and you can
learn programming online without the need to install anything at all.&lt;/p&gt;
&lt;!--  l. 81  --&gt;
&lt;p class='indent'&gt;What I’m saying is, ‘no matter your current resources, if you are sufficiently motivated you can find a way to learn programming.’ It may be difficult at first, but it will get easier (and then harder as you tackle more complex problems).&lt;/p&gt;</content><author><name>Mark Bools</name><email>mark@saltyvagrant.com</email></author><category term="opinion" /><summary type="html">TL;DR A few thoughts on learning to program and the ‘ease’ of prgramming. Inspired by this article.</summary></entry><entry><title type="html">Outline of a CI/CD Pipeline for Video Processing</title><link href="https://saltyvagrant.com/2021/04/06/video-processing-pipeline.html" rel="alternate" type="text/html" title="Outline of a CI/CD Pipeline for Video Processing" /><published>2021-04-06T00:00:00+01:00</published><updated>2021-04-06T00:00:00+01:00</updated><id>https://saltyvagrant.com/2021/04/06/video-processing-pipeline</id><content type="html" xml:base="https://saltyvagrant.com/2021/04/06/video-processing-pipeline.html">&lt;!--  l. 10  --&gt;
&lt;p class='indent'&gt;&lt;/p&gt;
&lt;div class='abstract'&gt;&lt;span class='ecbx-0900'&gt;TL;DR&lt;/span&gt; &lt;span class='ecrm-0900'&gt;In this article we are going to discuss the outline for a Continuous&lt;/span&gt; &lt;span class='ecrm-0900'&gt;Integration/Continuous Deployment (CI/CD)&lt;/span&gt;&lt;span class='footnote-mark'&gt;&lt;a href='#fn1x0' id='fn1x0-bk'&gt;&lt;sup class='textsuperscript'&gt;1&lt;/sup&gt;&lt;/a&gt;&lt;/span&gt;&lt;a id='x1-2f1'&gt;&lt;/a&gt; &lt;span class='ecrm-0900'&gt;pipeline to process videos. Specifically, we are going to discuss a pipeline&lt;/span&gt; &lt;span class='ecrm-0900'&gt;to take a main video,
an edit list, some inserts (ads, promos, etc.), some&lt;/span&gt; &lt;span class='ecrm-0900'&gt;title cards (opening, closing, transitions, etc.), and some metadata (like&lt;/span&gt; &lt;span class='ecrm-0900'&gt;the description, title, author, tags, categories, etc.) and use these to&lt;/span&gt; &lt;span class='ecrm-0900'&gt;assemble a number of final versions to be uploaded to various target&lt;/span&gt; &lt;span class='ecrm-0900'&gt;services (YouTube, Vimeo, lbry.tv, etc.).&lt;/span&gt;
&lt;hr /&gt;&lt;/div&gt;
&lt;!--  more  --&gt;
&lt;!--  l. 19  --&gt;
&lt;p class='indent'&gt;The basic flowchart for our pipeline looks something like this.&lt;/p&gt;
&lt;figure class='figure'&gt;&lt;a id='x1-3r1'&gt;&lt;/a&gt; &lt;!--  l. 23  --&gt;
&lt;p class='noindent'&gt;&lt;img src='/assets/images/2021/02/20210211-video-proc-basic-flowchart.svg' alt='PIC' /&gt;&lt;/p&gt;
&lt;figcaption class='caption'&gt;&lt;span class='id'&gt;Figure 1:&lt;/span&gt;&lt;span class='content'&gt;Video Process Pipeline Basic Flowchart&lt;/span&gt;&lt;/figcaption&gt;
&lt;!--  tex4ht:label?: x1-3r1   --&gt;&lt;/figure&gt;
&lt;!--  l. 28  --&gt;
&lt;p class='indent'&gt;We need to take care not to create a pipeline that requires massive storage. A typical CI/CD pipeline starts with a change in something like a git repository, perhaps the source code for our project. This implies that the resource holds &lt;span class='ecti-1000'&gt;all&lt;/span&gt; the source for the pipeline. In our video workflow this is probably not practicable as the resources are copied into the local fly worker container. Copying a growing set of videos would swiftly result in gigabytes of
files being copied through our pipeline; not cool.&lt;/p&gt;
&lt;!--  l. 30  --&gt;
&lt;p class='indent'&gt;To avoid the potential growth of data we will key everything from our metadata, using this as control to trigger a pipeline run and the content of the metadata will drive tasks in our pipeline to selectively upload other materials from remote ‘pools’.&lt;/p&gt;
&lt;!--  l. 32  --&gt;
&lt;p class='indent'&gt;We will still be importing some resources in their entirety:&lt;/p&gt;
&lt;dl class='description'&gt;
&lt;dt class='description'&gt;&lt;span class='ecbx-1000'&gt;metadata&lt;/span&gt;&lt;/dt&gt;
&lt;dd class='description'&gt;This may end up being several files, or even several resources. Things like Edit Decision List (EDL)&lt;span class='footnote-mark'&gt;&lt;a href='#fn2x0' id='fn2x0-bk'&gt;&lt;sup class='textsuperscript'&gt;2&lt;/sup&gt;&lt;/a&gt;&lt;/span&gt;&lt;a id='x1-4f2'&gt;&lt;/a&gt; used to determine cut points for inserts, metadata for deployment and announcements, data describing which videos are to be edited and which videos are to be inserted in promo or ad slots, that sort of thing.&lt;/dd&gt;
&lt;dt class='description'&gt;&lt;span class='ecbx-1000'&gt;templates&lt;/span&gt;&lt;/dt&gt;
&lt;dd class='description'&gt;This resource provides things like the LaTeX template used to generate title cards.&lt;/dd&gt;
&lt;/dl&gt;
&lt;!--  l. 39  --&gt;
&lt;p class='indent'&gt;On the output side. Do we want to keep all the generated video locally? Not really. So long as all the source material exists we do not really need to keep the final product (it is after all being uploaded to remote services), but we do want to have some may of verifying remote copies (i.e. those that have been deployed so that we can determine if they need to be redeployed).&lt;/p&gt;
&lt;h3 class='sectionHead'&gt;&lt;a id='x1-1000'&gt;&lt;/a&gt;The Development Environment&lt;/h3&gt;
&lt;p&gt;&lt;a id='x1-1000doc'&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!--  l. 44  --&gt;
&lt;p class='noindent'&gt;We’ll start with a Python development environment I anticipate several tools we need will be better as Python scripts than Bash scripts.&lt;/p&gt;
&lt;!--  l. 46  --&gt;
&lt;p class='indent'&gt;Obtain the base Python VM&lt;span class='footnote-mark'&gt;&lt;a href='#fn3x0' id='fn3x0-bk'&gt;&lt;sup class='textsuperscript'&gt;3&lt;/sup&gt;&lt;/a&gt;&lt;/span&gt;&lt;a id='x1-1001f3'&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;pre class='fancyvrb' id='fancyvrb1'&gt;&lt;a id='x1-1004r1'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;1&lt;/span&gt;&lt;span class='ectt-1000'&gt;git clone https://gitlab.com/python-utils2/pythonvm.git videoprocessor&lt;/span&gt;&lt;/pre&gt;
&lt;!--  l. 52  --&gt;
&lt;p class='indent'&gt;You may need to change the &lt;span class='inline-cmd'&gt;Vagrantfile&lt;/span&gt; to map the &lt;span class='inline-cmd'&gt;concourse&lt;/span&gt; port to something other than &lt;span class='inline-cmd'&gt;9080&lt;/span&gt;. If you already have something mapped to that port &lt;span class='inline-cmd'&gt;vagrant&lt;/span&gt; will complain when starting the VM.&lt;/p&gt;
&lt;!--  l. 54  --&gt;
&lt;p class='indent'&gt;Move into the new VM (this first run will take several minutes as the system is updated and various Python tools are installed).&lt;/p&gt;
&lt;pre class='fancyvrb' id='fancyvrb2'&gt;&lt;a id='x1-1008r1'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;1&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;cd&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; videoprocessor&lt;/span&gt; 
&lt;a id='x1-1010r2'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;2&lt;/span&gt;&lt;span class='ectt-1000'&gt;vagrant up&lt;/span&gt;&lt;/pre&gt;
&lt;!--  l. 61  --&gt;
&lt;p class='indent'&gt;Once your VM is up and running, &lt;span class='inline-cmd'&gt;ssh&lt;/span&gt; into it.&lt;/p&gt;
&lt;pre class='fancyvrb' id='fancyvrb3'&gt;&lt;a id='x1-1013r1'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;1&lt;/span&gt;&lt;span class='ectt-1000'&gt;vagrant ssh&lt;/span&gt;&lt;/pre&gt;
&lt;!--  l. 67  --&gt;
&lt;p class='indent'&gt;From this point on we will work almost exclusively in this VM, so I will highlight only operations &lt;span class='ecti-1000'&gt;not&lt;/span&gt; run in the VM/&lt;/p&gt;
&lt;!--  l. 70  --&gt;
&lt;p class='noindent'&gt;&lt;/p&gt;
&lt;h3 class='sectionHead'&gt;&lt;a id='x1-2000'&gt;&lt;/a&gt;Taking a look around&lt;/h3&gt;
&lt;p&gt;&lt;a id='x1-2000doc'&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!--  l. 73  --&gt;
&lt;p class='noindent'&gt;You will find that this VM has a few things already installed.&lt;/p&gt;
&lt;dl class='description'&gt;
&lt;dt class='description'&gt;&lt;span class='ecbx-1000'&gt;Concourse&lt;/span&gt;&lt;/dt&gt;
&lt;dd class='description'&gt;This is the ‘doer of things’ (their description) that we will use to manage and run our build pipeline.&lt;/dd&gt;
&lt;dt class='description'&gt;&lt;span class='ecbx-1000'&gt;Docker&lt;/span&gt;&lt;/dt&gt;
&lt;dd class='description'&gt;Used to run the Concourse CI system on this development VM. We will also use this to create containers to use in the Concourse pipeline.&lt;/dd&gt;
&lt;dt class='description'&gt;&lt;span class='ecbx-1000'&gt;Python&lt;/span&gt;&lt;/dt&gt;
&lt;dd class='description'&gt;We will use this to create the more complicated scripts in our pipeline.&lt;/dd&gt;
&lt;dt class='description'&gt;&lt;span class='ecbx-1000'&gt;Poetry&lt;/span&gt;&lt;/dt&gt;
&lt;dd class='description'&gt;A tool for Python package management.&lt;/dd&gt;
&lt;/dl&gt;
&lt;!--  l. 82  --&gt;
&lt;p class='indent'&gt;A few commands help confirm everything is installed.&lt;/p&gt;
&lt;pre class='fancyvrb' id='fancyvrb4'&gt;&lt;a id='x1-2007r1'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;1&lt;/span&gt;&lt;span class='ectt-1000'&gt;docker --version&lt;/span&gt; 
&lt;a id='x1-2009r2'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;2&lt;/span&gt;&lt;span class='ectt-1000'&gt;docker ps&lt;/span&gt; 
&lt;a id='x1-2011r3'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;3&lt;/span&gt;&lt;span class='ectt-1000'&gt;fly --version&lt;/span&gt; 
&lt;a id='x1-2013r4'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;4&lt;/span&gt;&lt;span class='ectt-1000'&gt;python --version&lt;/span&gt; 
&lt;a id='x1-2015r5'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;5&lt;/span&gt;&lt;span class='ectt-1000'&gt;poetry --version&lt;/span&gt;&lt;/pre&gt;
&lt;!--  l. 92  --&gt;
&lt;p class='indent'&gt;And you should see output something like the following (I’ve allowed the version to ‘float’, so you’re versions will likely be different to those shown below)..&lt;/p&gt;
&lt;div class='svout-title'&gt;
&lt;div&gt;docker&lt;/div&gt;
&lt;/div&gt;
&lt;pre class='fancyvrb' id='fancyvrb5'&gt;&lt;a id='x1-2021r1'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;1&lt;/span&gt;&lt;span class='ectt-1000'&gt;Docker version &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;20&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;.10.3, build 48d30b5&lt;/span&gt; 
&lt;a id='x1-2023r2'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;2&lt;/span&gt;&lt;span class='ectt-1000'&gt;CONTAINER ID   IMAGE                 COMMAND                  CREATED       STATUS       PORTS                    NAMES&lt;/span&gt; 
&lt;a id='x1-2025r3'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;3&lt;/span&gt;&lt;span class='ectt-1000'&gt;fcf478d39d95   concourse/concourse   &lt;/span&gt;&lt;span class='textcolor-ba2121'&gt;&lt;span class='ectt-1000'&gt;&quot;dumb-init /usr/loca…&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;   &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;2&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; hours ago   Up &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;2&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; hours   &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;.0.0.0:8080-&amp;gt;8080/tcp   concourse_ci_concourse_1&lt;/span&gt; 
&lt;a id='x1-2027r4'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;4&lt;/span&gt;&lt;span class='ectt-1000'&gt;79df83906661   postgres              &lt;/span&gt;&lt;span class='textcolor-ba2121'&gt;&lt;span class='ectt-1000'&gt;&quot;docker-entrypoint.s…&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;   &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;2&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; hours ago   Up &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;2&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; hours   &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;5432&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;/tcp                 concourse_ci_concourse-db_1&lt;/span&gt;&lt;/pre&gt;
&lt;div class='svout-title'&gt;
&lt;div&gt;fly –version&lt;/div&gt;
&lt;/div&gt;
&lt;pre class='fancyvrb' id='fancyvrb6'&gt;&lt;a id='x1-2030r1'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;1&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;6&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;.7.5&lt;/span&gt;&lt;/pre&gt;
&lt;div class='svout-title'&gt;
&lt;div&gt;python –version&lt;/div&gt;
&lt;/div&gt;
&lt;pre class='fancyvrb' id='fancyvrb7'&gt;&lt;a id='x1-2033r1'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;1&lt;/span&gt;&lt;span class='ectt-1000'&gt;Python &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;3&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;.8.2&lt;/span&gt;&lt;/pre&gt;
&lt;div class='svout-title'&gt;
&lt;div&gt;poetry –version&lt;/div&gt;
&lt;/div&gt;
&lt;pre class='fancyvrb' id='fancyvrb8'&gt;&lt;a id='x1-2036r1'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;1&lt;/span&gt;&lt;span class='ectt-1000'&gt;Poetry version &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;1&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;.1.4&lt;/span&gt;&lt;/pre&gt;
&lt;!--  l. 114  --&gt;
&lt;p class='noindent'&gt;&lt;/p&gt;
&lt;h3 class='sectionHead'&gt;&lt;a id='x1-3000'&gt;&lt;/a&gt;The First Build Task: Making title cards&lt;/h3&gt;
&lt;p&gt;&lt;a id='x1-3000doc'&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!--  l. 117  --&gt;
&lt;p class='noindent'&gt;This is fairly straightforward; take a LaTeX template, feed it a title and logo and have it produce a PNG titlecard. Our inputs are therefore:&lt;/p&gt;
&lt;ul class='itemize1'&gt;
&lt;li class='itemize'&gt;LaTeX template&lt;/li&gt;
&lt;li class='itemize'&gt;Logo&lt;/li&gt;
&lt;li class='itemize'&gt;Title string&lt;/li&gt;
&lt;/ul&gt;
&lt;!--  l. 125  --&gt;
&lt;p class='indent'&gt;Our outputs are:&lt;/p&gt;
&lt;ul class='itemize1'&gt;
&lt;li class='itemize'&gt;A title card PNG&lt;/li&gt;
&lt;/ul&gt;
&lt;!--  l. 131  --&gt;
&lt;p class='indent'&gt;The tools required to transform our inputs to our outputs are:&lt;/p&gt;
&lt;ul class='itemize1'&gt;
&lt;li class='itemize'&gt;LaTeX processor&lt;/li&gt;
&lt;li class='itemize'&gt;ImageMagic, to convert the LaTeX output (a PDF) to a PNG&lt;/li&gt;
&lt;/ul&gt;
&lt;!--  l. 138  --&gt;
&lt;p class='indent'&gt;We could create a specialised Docker Image for this, but I will reuse my general purpose document generator image &lt;span class='inline-cmd'&gt;saltyvagrant/latex-docker&lt;/span&gt; (this is itself a custom made image, but is not specialised in the sense that it contains almost the entire LaTeX Live installation making it a very large image, but I reuse it for many Concourse tasks).&lt;/p&gt;
&lt;!--  l. 140  --&gt;
&lt;p class='indent'&gt;I have a logo already available (I prefer to preserve all images in SVG format until final conversion to a target format). The LaTeX template it fairly simple.&lt;/p&gt;
&lt;div class='svlisting-title'&gt;
&lt;div&gt;titlecard.tex&lt;/div&gt;
&lt;/div&gt;
&lt;pre class='fancyvrb' id='fancyvrb9'&gt;&lt;a id='x1-3026r1'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;1&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;\documentclass&lt;/span&gt;&lt;/span&gt;&lt;span class='textcolor-7c8e28'&gt;&lt;span class='ectt-1000'&gt;[oneside]&lt;/span&gt;&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;{&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;standalone&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;}&lt;/span&gt;&lt;/span&gt; 
&lt;a id='x1-3028r2'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;2&lt;/span&gt; 
&lt;a id='x1-3030r3'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;3&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;\usepackage{&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;saltyvagrant&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;}&lt;/span&gt;&lt;/span&gt; 
&lt;a id='x1-3032r4'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;4&lt;/span&gt; 
&lt;a id='x1-3034r5'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;5&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;\usepackage{&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;graphicx&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;}&lt;/span&gt;&lt;/span&gt; 
&lt;a id='x1-3036r6'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;6&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;\usepackage{&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;xcolor&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;}&lt;/span&gt;&lt;/span&gt; 
&lt;a id='x1-3038r7'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;7&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;\usepackage{&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;tgadventor&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;}&lt;/span&gt;&lt;/span&gt; 
&lt;a id='x1-3040r8'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;8&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;\renewcommand*\familydefault{\sfdefault}&lt;/span&gt;&lt;/span&gt; 
&lt;a id='x1-3042r9'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;9&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;\usepackage&lt;/span&gt;&lt;/span&gt;&lt;span class='textcolor-7c8e28'&gt;&lt;span class='ectt-1000'&gt;[T1]&lt;/span&gt;&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;{&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;fontenc&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;}&lt;/span&gt;&lt;/span&gt; 
&lt;a id='x1-3044r10'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;10&lt;/span&gt; 
&lt;a id='x1-3046r11'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;11&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;\SetWatermarkScale{&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; 0.5 &lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;}&lt;/span&gt;&lt;/span&gt; 
&lt;a id='x1-3048r12'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;12&lt;/span&gt; 
&lt;a id='x1-3050r13'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;13&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;\begin{&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;document&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;}&lt;/span&gt;&lt;/span&gt; 
&lt;a id='x1-3052r14'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;14&lt;/span&gt;&lt;span class='ectt-1000'&gt;  &lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;\begin{&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;minipage&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;}{&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;572bp&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;}&lt;/span&gt;&lt;/span&gt; 
&lt;a id='x1-3054r15'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;15&lt;/span&gt;&lt;span class='ectt-1000'&gt;    &lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;\includegraphics&lt;/span&gt;&lt;/span&gt;&lt;span class='textcolor-7c8e28'&gt;&lt;span class='ectt-1000'&gt;[height=720bp]&lt;/span&gt;&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;{&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;logo&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;_&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;and&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;_&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;mascot/salty-logo-avatar-clipped.png&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;}&lt;/span&gt;&lt;/span&gt; 
&lt;a id='x1-3056r16'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;16&lt;/span&gt;&lt;span class='ectt-1000'&gt;  &lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;\end{&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;minipage&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;}&lt;/span&gt;&lt;/span&gt; 
&lt;a id='x1-3058r17'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;17&lt;/span&gt;&lt;span class='ectt-1000'&gt;  &lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;\begin{&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;minipage&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;[c][720bp]&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;{&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;705bp&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;}&lt;/span&gt;&lt;/span&gt; 
&lt;a id='x1-3060r18'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;18&lt;/span&gt;&lt;span class='ectt-1000'&gt;    &lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;\fontsize{&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;100&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;}{&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;130&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;}\selectfont&lt;/span&gt;&lt;/span&gt; 
&lt;a id='x1-3062r19'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;19&lt;/span&gt;&lt;span class='ectt-1000'&gt;    &lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;\color{&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;svblue&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;}&lt;/span&gt;&lt;/span&gt; 
&lt;a id='x1-3064r20'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;20&lt;/span&gt;&lt;span class='ectt-1000'&gt;    &lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;\begin{&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;center&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;}&lt;/span&gt;&lt;/span&gt; 
&lt;a id='x1-3066r21'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;21&lt;/span&gt;&lt;span class='ectt-1000'&gt;      &lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;\getenv{&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;TITLE&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;}&lt;/span&gt;&lt;/span&gt; 
&lt;a id='x1-3068r22'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;22&lt;/span&gt;&lt;span class='ectt-1000'&gt;    &lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;\end{&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;center&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;}&lt;/span&gt;&lt;/span&gt; 
&lt;a id='x1-3070r23'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;23&lt;/span&gt;&lt;span class='ectt-1000'&gt;  &lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;\end{&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;minipage&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;}&lt;/span&gt;&lt;/span&gt; 
&lt;a id='x1-3072r24'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;24&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;\end{&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;document&lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;!--  l. 169  --&gt;
&lt;p class='indent'&gt;The title itself is provided from a metadata file and inserted into the LaTeX process using the &lt;span class='inline-cmd'&gt;TITLE&lt;/span&gt; environment variable. We will discuss the LaTeX process in more detail in a later article in this series.&lt;/p&gt;
&lt;!--  l. 171  --&gt;
&lt;p class='noindent'&gt;&lt;/p&gt;
&lt;h4 class='subsectionHead'&gt;&lt;a id='x1-4000'&gt;&lt;/a&gt;Where to start a build&lt;/h4&gt;
&lt;p&gt;&lt;a id='x1-4000doc'&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!--  l. 174  --&gt;
&lt;p class='noindent'&gt;One decision you need to make when designing build systems is ‘where does the build start?’ By this I mean what do you consider the raw material for your build. With straightforward software builds the most obvious raw material is your source code. Less obvious raw materials are things like internationalisation strings, embedded images, and the build itself (e.g. the &lt;span class='inline-cmd'&gt;Makefile&lt;/span&gt;). In the real world it is seldom this obvious.&lt;/p&gt;
&lt;!--  l. 176  --&gt;
&lt;p class='indent'&gt;Even in a relatively straightforward build you have complications to consider. If you’re building for multiple target platforms then it is likely that your &lt;span class='inline-cmd'&gt;Makefile&lt;/span&gt; will be generated using configuration specific to the target platform. This either moves your raw materials back one level (an additional configuration and &lt;span class='inline-cmd'&gt;Makefile&lt;/span&gt; generation step) or you manually create several &lt;span class='inline-cmd'&gt;Makefile&lt;/span&gt;s and
thereby shift some of the burden from the build process to whomever makes the builds (not a good option, but an option).&lt;/p&gt;
&lt;!--  l. 178  --&gt;
&lt;p class='indent'&gt;In the case of video processor some of the raw materials are also apparently obvious; the main video and audio, the metadata (title, description, etc.). Other, less obvious, sources include the build system itself. The various scripts and tools used to perform the build. These scripts may well also be making decisions about what and how to perform the build.&lt;/p&gt;
&lt;!--  l. 180  --&gt;
&lt;p class='indent'&gt;Beyond these ‘obvious’ points we may decide to create the title videos manually, so these now become sources rather than the metadata and templates etc. proposed above. Where you start your build will often be a matter of judgement, experience, project requirements, and technical limitations. A simple example from our current build; why not start from raw video and audio footage and have the build cut together the main video using an EDL also provided as source? This is entirely possible
but also impractical for our purpose. Editing the main video together is simpler using an Non-Linear Editor (NLE)&lt;span class='footnote-mark'&gt;&lt;a href='#fn4x0' id='fn4x0-bk'&gt;&lt;sup class='textsuperscript'&gt;4&lt;/sup&gt;&lt;/a&gt;&lt;/span&gt;&lt;a id='x1-4001f4'&gt;&lt;/a&gt;, this video processing pipeline is performing the tedious tasks that can be easily automated whereas pulling raw video and audio together into a coherent video is (at least for me) much simpler using manual tools. (That said, if I were to be truly bloody-minded I could
have the NLE generate the EDL and then have the build effectively repeat the main video cut, but that seems redundant to my workflow.)&lt;/p&gt;
&lt;!--  l. 184  --&gt;
&lt;p class='noindent'&gt;&lt;/p&gt;
&lt;h4 class='subsectionHead'&gt;&lt;a id='x1-5000'&gt;&lt;/a&gt;Musings on metadata&lt;/h4&gt;
&lt;p&gt;&lt;a id='x1-5000doc'&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!--  l. 187  --&gt;
&lt;p class='noindent'&gt;We now encounter our first issue. Generally we want changes to the ‘make title’ task sources to trigger a build (we can trigger tasks in several ways, but source changes are the most common). Our source are; the metadata, the logo, and the template. Here’s the issue, if the template changes do we &lt;span class='ecti-1000'&gt;really&lt;/span&gt; want to trigger the task? If so, should it rebuild &lt;span class='ecti-1000'&gt;all&lt;/span&gt; title cards using the new template? (Bearing in mind that creating
new title cards implies that any videos that used those title cards should also be regenerated.) What about if the logo changes? Same issue as the template. What about the metadata? The only piece of metadata we want to trigger a new title card is the title, any other changes can be ignored for now.&lt;/p&gt;
&lt;!--  l. 189  --&gt;
&lt;p class='indent'&gt;I think that generally I do not want template or logo changes to trigger complete rebuilds (maybe later I’ll look at manually triggering these wholesale changes, following a rebranding for example, but day-to-day it’s safe to assume changes to template or logo should effect only new title cards).&lt;/p&gt;
&lt;!--  l. 191  --&gt;
&lt;p class='indent'&gt;That leaves us with metadata changes. Title cards come in two types; those specific to a video (for example the lead title card) and more general ‘inserts’ (like ‘…and now a word from our sponsor’) that may be reused in several productions. Should we therefore maintain metadata as one large ‘database’, or ‘one data file per production’, or ‘one data file per title card’?&lt;/p&gt;
&lt;!--  l. 193  --&gt;
&lt;p class='indent'&gt;We could make a case for any of these solutions. I’m going with one per production but allowing a ’production’ to be one or more stand alone title cards. This seems like a reasonable compromise to me as it keeps everything more or less in one place for most videos but allows some flexibility to generate stand alone items too. The corollary to this being that each production can refer to other productions (so video A can use a title card produced by title B). I may live to regret this
decision, but this is an iterative process and we need somewhere to start.&lt;/p&gt;
&lt;!--  l. 195  --&gt;
&lt;p class='indent'&gt;Why not go for one big lump of metadata? Mainly I think it would quickly become unwieldy and difficult to edit by hand (no doubt leading to yet another utility to maintain just the metadata and that roads leads to using databases, all of which seems like a bit of overkill at the moment). Also, the design of this whole pipeline means I may well not want to keep all metadata feeding in to the start of the pipeline (more on this in a while).&lt;/p&gt;
&lt;!--  l. 198  --&gt;
&lt;p class='noindent'&gt;&lt;/p&gt;
&lt;h4 class='subsectionHead'&gt;&lt;a id='x1-6000'&gt;&lt;/a&gt;The new task&lt;/h4&gt;
&lt;p&gt;&lt;a id='x1-6000doc'&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!--  l. 201  --&gt;
&lt;p class='noindent'&gt;Our new task has one more input, the script to perform the build. It is possible, when your task’s image is specialised enough, to continue with the simple ‘one command’ but this task needs something more complex. Specifically, we need the task to scan metadata and make decisions about which title cards to produce.&lt;/p&gt;
&lt;!--  l. 206  --&gt;
&lt;p class='noindent'&gt;&lt;/p&gt;
&lt;h3 class='sectionHead'&gt;&lt;a id='x1-7000'&gt;&lt;/a&gt;Title Videos&lt;/h3&gt;
&lt;p&gt;&lt;a id='x1-7000doc'&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!--  l. 209  --&gt;
&lt;p class='noindent'&gt;We have a choice here. We can either make short stand alone videos from our title cards or we can use some &lt;span class='inline-cmd'&gt;ffmpeg&lt;/span&gt; magic later on to insert the title cards as short static section.&lt;/p&gt;
&lt;!--  l. 211  --&gt;
&lt;p class='indent'&gt;If we make short videos now it may reduce time rebuilding later (for example reusing the titles in another project) but this also implies storing the title videos somewhere so they can be reused. This seems unnecessary to shave a few seconds of downstream activities.&lt;/p&gt;
&lt;!--  l. 213  --&gt;
&lt;p class='indent'&gt;If we insert the titles ‘on-the-fly’ we make the assembly of the final video more complex (and consequently potentially more error prone) and more demanding on our downstream activity (the video must be reconstructed each time).&lt;/p&gt;
&lt;!--  l. 215  --&gt;
&lt;p class='indent'&gt;I think that, for now, we will create them on-the-fly and only create them separately if this proves troublesome.&lt;/p&gt;
&lt;!--  l. 221  --&gt;
&lt;p class='noindent'&gt;&lt;/p&gt;
&lt;h3 class='sectionHead'&gt;&lt;a id='x1-8000'&gt;&lt;/a&gt;Assembling the Final Video(s)&lt;/h3&gt;
&lt;p&gt;&lt;a id='x1-8000doc'&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!--  l. 225  --&gt;
&lt;p class='noindent'&gt;We may be assembling several version of the final video. Different ads, sponsors, or promotions being placed into, or omitted from, the main video according to the target platform. All this to be driven by our metadata.&lt;/p&gt;
&lt;!--  l. 230  --&gt;
&lt;p class='noindent'&gt;&lt;/p&gt;
&lt;h3 class='sectionHead'&gt;&lt;a id='x1-9000'&gt;&lt;/a&gt;Deploying the Final Video(s)&lt;/h3&gt;
&lt;p&gt;&lt;a id='x1-9000doc'&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!--  l. 233  --&gt;
&lt;p class='noindent'&gt;Our metadata can provide common information for each remote source (such as authentication details). It can also present specific information for each target, for example descriptions and ‘flags’ (those pop-over links available on platforms like YouTube).&lt;/p&gt;
&lt;!--  l. 237  --&gt;
&lt;p class='noindent'&gt;&lt;/p&gt;
&lt;h3 class='sectionHead'&gt;&lt;a id='x1-10000'&gt;&lt;/a&gt;Announcing New Videos&lt;/h3&gt;
&lt;p&gt;&lt;a id='x1-10000doc'&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!--  l. 240  --&gt;
&lt;p class='noindent'&gt;Once the videos are deployed we can announce their availability. As with deployment our metadata can provide authentication details for the various announcement channels along with details of what each announcement should contain. One of the main things in this section is to ensure we do not announce multiple times if something goes wrong.&lt;/p&gt;
&lt;!--  l. 243  --&gt;
&lt;p class='noindent'&gt;&lt;/p&gt;
&lt;h3 class='sectionHead'&gt;&lt;a id='x1-11000'&gt;&lt;/a&gt;Final Thoughts&lt;/h3&gt;
&lt;p&gt;&lt;a id='x1-11000doc'&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!--  l. 246  --&gt;
&lt;p class='noindent'&gt;In this article I’ve started thinking about the CI/CD process for making and publishing videos. Many of the details remain to be established but the broad outline seems like a good start.&lt;/p&gt;
&lt;div class='footnotes'&gt;&lt;!--  l. 16  --&gt;
&lt;p class='indent'&gt;&lt;span class='footnote-mark'&gt;&lt;a href='#fn1x0-bk' id='fn1x0'&gt;&lt;sup class='textsuperscript'&gt;1&lt;/sup&gt;&lt;/a&gt;&lt;/span&gt;&lt;span class='ecrm-0800'&gt;Automated process for building, testing, and deploying assets.&lt;/span&gt;&lt;/p&gt;
&lt;!--  l. 35  --&gt;
&lt;p class='noindent'&gt;&lt;span class='footnote-mark'&gt;&lt;a href='#fn2x0-bk' id='fn2x0'&gt;&lt;sup class='textsuperscript'&gt;2&lt;/sup&gt;&lt;/a&gt;&lt;/span&gt;&lt;span class='ecrm-0800'&gt;A list of ‘edits’; cut, insert, delete, etc. Usually presented in a standard text format such&lt;/span&gt; &lt;span class='ecrm-0800'&gt;as CMX 3600&lt;/span&gt;&lt;/p&gt;
&lt;!--  l. 46  --&gt;
&lt;p class='indent'&gt;&lt;span class='footnote-mark'&gt;&lt;a href='#fn3x0-bk' id='fn3x0'&gt;&lt;sup class='textsuperscript'&gt;3&lt;/sup&gt;&lt;/a&gt;&lt;/span&gt;&lt;span class='ecrm-0800'&gt;If you want to be sure you’re using the setup in this tutorial then&lt;/span&gt; &lt;span class='inline-cmd'&gt;&lt;span class='ecrm-0800'&gt;git checkout -b v0.1.0&lt;/span&gt;&lt;/span&gt; &lt;span class='ecrm-0800'&gt;once you’re in the workspace.&lt;/span&gt;&lt;/p&gt;
&lt;!--  l. 180  --&gt;
&lt;p class='indent'&gt;&lt;span class='footnote-mark'&gt;&lt;a href='#fn4x0-bk' id='fn4x0'&gt;&lt;sup class='textsuperscript'&gt;4&lt;/sup&gt;&lt;/a&gt;&lt;/span&gt;&lt;span class='ecrm-0800'&gt;Tool/technique for editing video that allows the user to choose any point in the project to&lt;/span&gt; &lt;span class='ecrm-0800'&gt;work on.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;</content><author><name>Mark Bools</name><email>mark@saltyvagrant.com</email></author><category term="CI/CD" /><summary type="html">TL;DR In this article we are going to discuss the outline for a Continuous Integration/Continuous Deployment (CI/CD)1 pipeline to process videos. Specifically, we are going to discuss a pipeline to take a main video, an edit list, some inserts (ads, promos, etc.), some title cards (opening, closing, transitions, etc.), and some metadata (like the description, title, author, tags, categories, etc.) and use these to assemble a number of final versions to be uploaded to various target services (YouTube, Vimeo, lbry.tv, etc.).</summary></entry><entry><title type="html">Being explicit</title><link href="https://saltyvagrant.com/2021/02/28/being-explicit.html" rel="alternate" type="text/html" title="Being explicit" /><published>2021-02-28T00:00:00+00:00</published><updated>2021-02-28T00:00:00+00:00</updated><id>https://saltyvagrant.com/2021/02/28/being-explicit</id><content type="html" xml:base="https://saltyvagrant.com/2021/02/28/being-explicit.html">&lt;div class='abstract'&gt;&lt;span class='ecbx-0900'&gt;TL;DR&lt;/span&gt; &lt;span class='ecrm-0900'&gt;There are many opportunities for developers to rely on&lt;/span&gt; &lt;span class='ecrm-0900'&gt;implicit defaults. In this article I make the general proposition that it is&lt;/span&gt; &lt;span class='ecrm-0900'&gt;better to be explicit rather than rely on defaults.&lt;/span&gt;
&lt;hr /&gt;&lt;/div&gt;
&lt;!--  more  --&gt;
&lt;!--  l. 15  --&gt;
&lt;p class='indent'&gt;&lt;/p&gt;
&lt;!--  l. 18  --&gt;
&lt;p class='indent'&gt;I am as guilty as anyone of relying on defaults. That said, it’s a bad habit.&lt;/p&gt;
&lt;!--  l. 20  --&gt;
&lt;p class='indent'&gt;The main problem is that defaults change from time to time. As the creator of a service (API, library, etc.) it makes sense to provide default values. They make the service easier to consume and simplifies writing the service. As the consumer of a service defaults can certainly appear to make using the service simpler but at the cost of potential breakages when the defaults change.&lt;/p&gt;
&lt;!--  l. 23  --&gt;
&lt;p class='indent'&gt;Let’s look at a trivial (and horribly contrived) example to make the point.&lt;/p&gt;
&lt;!--  l. 25  --&gt;
&lt;p class='indent'&gt;Suppose I have created a library to draw a circle.&lt;/p&gt;
&lt;pre id='fancyvrb1' class='fancyvrb'&gt;&lt;a id='x1-5r1'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;1&lt;/span&gt;&lt;span class='ectt-1000'&gt;def drawCircle&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class='textcolor-19167c'&gt;&lt;span class='ectt-1000'&gt;radius&lt;/span&gt;&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;=10)&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;:&lt;/span&gt; 
&lt;a id='x1-7r2'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;2&lt;/span&gt;&lt;span class='ectt-1000'&gt;  pass&lt;/span&gt;&lt;/pre&gt;
&lt;!--  l. 32  --&gt;
&lt;p class='indent'&gt;My interface provides a default radius (perhaps the most common size for some graphic I want to create). This is convenient and users of my library use this default, calling the routine as &lt;span class='inline-cmd'&gt;drawCircle()&lt;/span&gt;.&lt;/p&gt;
&lt;!--  l. 34  --&gt;
&lt;p class='indent'&gt;The issue is that &lt;span class='inline-cmd'&gt;drawCircle&lt;/span&gt; is now ‘locked-in’ to this default. If I decide to change the default (perhaps my application need cicles of diameter 20 now and the quickest way to make the change in &lt;span class='ecti-1000'&gt;my&lt;/span&gt; application is the change the default). The problem is doing so will wreak havoc in applications that used the default and continue to need circles of radius 10.&lt;/p&gt;
&lt;!--  l. 37  --&gt;
&lt;p class='indent'&gt;As a real-world example of the changing defaults issue, consider the cookie &lt;span class='inline-cmd'&gt;SameSite&lt;/span&gt; attribute. Originally cookies were broadly exchanged but problems emerged with cookies being misappropriated so the &lt;span class='inline-cmd'&gt;SameSite&lt;/span&gt; setting was added. Initially the default was &lt;span class='inline-cmd'&gt;None&lt;/span&gt; (to match behviour before &lt;span class='inline-cmd'&gt;SameSite&lt;/span&gt; became available) but in Chrome 80 this was to change to &lt;span class='inline-cmd'&gt;Lax&lt;/span&gt;. The problem with this change being that it would break many existing resource links (e.g. &lt;span class='inline-cmd'&gt;&amp;lt;img&amp;gt;&lt;/span&gt;) while letting links (e.g. &lt;span class='inline-cmd'&gt;&amp;lt;a&amp;gt;&lt;/span&gt;) continue to work. This change was pushed out (due to the &lt;a href='https://riverbank.biz/ContentDocumentHandler.ashx?documentId=67559'&gt;disruption&lt;/a&gt; the change caused) to Chrome 85).&lt;/p&gt;</content><author><name>Mark Bools</name><email>mark@saltyvagrant.com</email></author><category term="opinion" /><category term="practices" /><summary type="html">TL;DR There are many opportunities for developers to rely on implicit defaults. In this article I make the general proposition that it is better to be explicit rather than rely on defaults.</summary></entry><entry><title type="html">Host Setup for SaltyVagrant</title><link href="https://saltyvagrant.com/2021/02/27/host-setup-for-saltyvagrant.html" rel="alternate" type="text/html" title="Host Setup for SaltyVagrant" /><published>2021-02-27T00:00:00+00:00</published><updated>2021-02-27T00:00:00+00:00</updated><id>https://saltyvagrant.com/2021/02/27/host-setup-for-saltyvagrant</id><content type="html" xml:base="https://saltyvagrant.com/2021/02/27/host-setup-for-saltyvagrant.html">&lt;div class='abstract'&gt;&lt;span class='ecbx-0900'&gt;TL;DR&lt;/span&gt; &lt;span class='ecrm-0900'&gt;Many SaltyVagrant articles and books use a common set of&lt;/span&gt; &lt;span class='ecrm-0900'&gt;tools. This article outlines the tools used.&lt;/span&gt;
&lt;hr /&gt;&lt;/div&gt;
&lt;!--  more  --&gt;
&lt;!--  l. 15  --&gt;
&lt;p class='indent'&gt;&lt;/p&gt;
&lt;!--  l. 18  --&gt;
&lt;p class='indent'&gt;You will need to install three tools to your computer:&lt;/p&gt;
&lt;ol class='enumerate1'&gt;
&lt;li class='enumerate' id='x1-3x1'&gt;&lt;a href='https://virtualbox.org'&gt;&lt;span class='inline-cmd'&gt;virtualbox&lt;/span&gt;&lt;/a&gt;—to run virtual machines.&lt;/li&gt;
&lt;li class='enumerate' id='x1-5x2'&gt;&lt;a href='https://vagrantup.com'&gt;&lt;span class='inline-cmd'&gt;vagrant&lt;/span&gt;&lt;/a&gt;—to supervise the creation and setup of virtual machines.&lt;/li&gt;
&lt;li class='enumerate' id='x1-7x3'&gt;&lt;a href='https://git-scm.com/'&gt;&lt;span class='inline-cmd'&gt;git&lt;/span&gt;&lt;/a&gt;—for version control (and more immediately to get the files needed to setup the virtual machines).&lt;/li&gt;
&lt;/ol&gt;
&lt;!--  l. 26  --&gt;
&lt;p class='indent'&gt;The installation instructions for these tools tend to vary over time so it’s best if you visit the websites, download the tool and follow the installation instructions relevant to your computer’s operating system.&lt;/p&gt;</content><author><name>Mark Bools</name><email>mark@saltyvagrant.com</email></author><category term="courses" /><summary type="html">TL;DR Many SaltyVagrant articles and books use a common set of tools. This article outlines the tools used.</summary></entry><entry><title type="html">The Horrors of Third-party Authentication</title><link href="https://saltyvagrant.com/2021/02/26/the-horrors-of-third-party-authentication.html" rel="alternate" type="text/html" title="The Horrors of Third-party Authentication" /><published>2021-02-26T00:00:00+00:00</published><updated>2021-02-26T00:00:00+00:00</updated><id>https://saltyvagrant.com/2021/02/26/the-horrors-of-third-party-authentication</id><content type="html" xml:base="https://saltyvagrant.com/2021/02/26/the-horrors-of-third-party-authentication.html">&lt;!--  l. 7  --&gt;
&lt;p class='noindent'&gt;&lt;/p&gt;
&lt;div class='abstract'&gt;&lt;span class='ecbx-0900'&gt;TL;DR&lt;/span&gt; &lt;span class='ecrm-0900'&gt;It is becoming increasingly common for sites to offer&lt;/span&gt; &lt;span class='ecrm-0900'&gt;third-party authentication (using, for example, your Google account to&lt;/span&gt; &lt;span class='ecrm-0900'&gt;log in to xyz.com). This is all very convenient but has some significant&lt;/span&gt; &lt;span class='ecrm-0900'&gt;downside.&lt;/span&gt;
&lt;hr /&gt;&lt;/div&gt;
&lt;!--  more  --&gt;
&lt;!--  l. 16  --&gt;
&lt;p class='indent'&gt;As I write this I am in the process of adding third-party authentication to SaltyVagrant.com, hold the cries of ‘hypocrite’ though as my issues are more to do with careless users than sites enabling them.&lt;/p&gt;
&lt;h3 class='sectionHead'&gt;&lt;a id='x1-1000'&gt;&lt;/a&gt;Privacy&lt;/h3&gt;
&lt;p&gt;&lt;a id='x1-1000doc'&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!--  l. 22  --&gt;
&lt;p class='noindent'&gt;Using third-party identity providers just puts even more personal information in the hands or these companies. Every site you use your social account to log in with immediately gains access to information about how often you visit the site, from where you access the site, and a potential wealth of other information. It is, fortunately, not likely that they will have access to the content the service for which they provide identity, but these other data are still very valuable and allow
the likes of Google and Facebook to assemble a profile of information about your internet use.&lt;/p&gt;
&lt;!--  l. 24  --&gt;
&lt;p class='noindent'&gt;&lt;/p&gt;
&lt;h3 class='sectionHead'&gt;&lt;a id='x1-2000'&gt;&lt;/a&gt;Security&lt;/h3&gt;
&lt;p&gt;&lt;a id='x1-2000doc'&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!--  l. 27  --&gt;
&lt;p class='noindent'&gt;While there is no direct concern about the robustness of most third-party identity providers (beyond the usual problems of users choosing poor passwords) there remains the concern that using one identity provider across multiple services is equivalent to using one password. If the social account you use to log in to many sites with becomes compromised then instantly all the sites you used this social account on are also compromised.&lt;/p&gt;
&lt;!--  l. 29  --&gt;
&lt;p class='noindent'&gt;&lt;/p&gt;
&lt;h3 class='sectionHead'&gt;&lt;a id='x1-3000'&gt;&lt;/a&gt;Availability&lt;/h3&gt;
&lt;p&gt;&lt;a id='x1-3000doc'&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!--  l. 32  --&gt;
&lt;p class='noindent'&gt;As a site using third-party authenticators you have other issue. Principal among these are availability. If the third-party become unavailable you lose customers. This applies generally (the provider becomes unavailable to all users) and specifically (one user is denies access to the third-party—an increasingly likely situation). In either case you lose business entirely because of the third-party’s behaviour.&lt;/p&gt;
&lt;!--  l. 35  --&gt;
&lt;p class='noindent'&gt;&lt;/p&gt;
&lt;h3 class='sectionHead'&gt;&lt;a id='x1-4000'&gt;&lt;/a&gt;Support&lt;/h3&gt;
&lt;p&gt;&lt;a id='x1-4000doc'&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!--  l. 38  --&gt;
&lt;p class='noindent'&gt;Then there is the support service problem. If a user has difficuly logging on, is this a problem with your service of with the identity service? It is difficult to explain to users that you &lt;span class='ecti-1000'&gt;cannot&lt;/span&gt; help them because it is Google, Facebook, or whomever, denying them login access, not you.&lt;/p&gt;
&lt;h2 class='likechapterHead'&gt;&lt;a id='x1-5000'&gt;&lt;/a&gt;Additional Resources&lt;/h2&gt;
&lt;!--  l. 44  --&gt;
&lt;p class='noindent'&gt;&lt;a id='likesection.5'&gt;&lt;/a&gt;&lt;a id='Q1-1-6'&gt;&lt;/a&gt;&lt;/p&gt;
&lt;dl class='thebibliography'&gt;
&lt;dt class='thebibliography' id='X0-iscis12p6:online'&gt;[LU]&lt;/dt&gt;
&lt;dd class='thebibliography' id='bib-1'&gt;&lt;!--  l. 44  --&gt;
&lt;p class='noindent'&gt;&lt;a id='cite.0@iscis12p6:online'&gt;&lt;/a&gt;A Levi and M Ufuk Çağlayani. &lt;span class='ecti-1000'&gt;The Problem of Trusted&lt;/span&gt; &lt;span class='ecti-1000'&gt;Third Party in Authentication and Digital Signature Protocols&lt;/span&gt;. &lt;span class='eccc1000-'&gt;&lt;span class='small-caps'&gt;url&lt;/span&gt;&lt;/span&gt;: &lt;a class='url' href='http://people.sabanciuniv.edu/levi/iscis12.pdf'&gt;&lt;span class='ectt-1000'&gt;http://people.sabanciuniv.edu/levi/iscis12.pdf&lt;/span&gt;&lt;/a&gt; (visited on 02/26/2021).&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;</content><author><name>Mark Bools</name><email>mark@saltyvagrant.com</email></author><summary type="html">TL;DR It is becoming increasingly common for sites to offer third-party authentication (using, for example, your Google account to log in to xyz.com). This is all very convenient but has some significant downside.</summary></entry><entry><title type="html">Amateur vs. Professional: Optimisation</title><link href="https://saltyvagrant.com/2021/02/22/amateur-or-professional.html" rel="alternate" type="text/html" title="Amateur vs. Professional: Optimisation" /><published>2021-02-22T00:00:00+00:00</published><updated>2021-02-22T00:00:00+00:00</updated><id>https://saltyvagrant.com/2021/02/22/amateur-or-professional</id><content type="html" xml:base="https://saltyvagrant.com/2021/02/22/amateur-or-professional.html">&lt;div class='abstract'&gt;&lt;span class='ecbx-0900'&gt;TL;DR&lt;/span&gt; &lt;span class='ecrm-0900'&gt;What distinguishes an amateur from a professional? Let’s&lt;/span&gt; &lt;span class='ecrm-0900'&gt;consider optimisation. (Obviously much of this is opinion.)&lt;/span&gt;
&lt;hr /&gt;&lt;/div&gt;
&lt;!--  more  --&gt;
&lt;!--  l. 15  --&gt;
&lt;p class='indent'&gt;&lt;/p&gt;
&lt;!--  l. 18  --&gt;
&lt;p class='indent'&gt;Optimisation is a topic often brought up online, and often incorrectly.&lt;/p&gt;
&lt;!--  l. 20  --&gt;
&lt;p class='indent'&gt;People will obsess about trivia, such as how to shave a few keystrokes from their ViM use or how to shave milliseconds from their code run-time, or avoid spawning sub-processes in the Bash scripts. Don’t get me wrong, there is a time and place for being concerned about each of these, but it is not something the professional worries about most of the time. The majority of these debates are amateurs trying the flex, showing their ‘amazing’ skills. In truth, the harder people try to impress
like this the less professionals care.&lt;/p&gt;
&lt;!--  l. 22  --&gt;
&lt;p class='indent'&gt;A professional’s mantra is, ’get it working’—this is, after all, what we’re paid to do.&lt;/p&gt;
&lt;!--  l. 24  --&gt;
&lt;p class='indent'&gt;Let’s consider a professional approach to tool use. Yes, you can save time and effort by using your tools efficiently. It &lt;span class='ecti-1000'&gt;is&lt;/span&gt; worth learning efficient keystrokes on ViM &lt;span class='ecti-1000'&gt;but&lt;/span&gt; only if you repeat the operation those keystrokes achieve thousands of times. Spending time to learn (and by ‘learn’ I mean commit to muscle memory so it becomes automatic) a keystroke pattern takes time and effort. The time and effort you commit to this
learning had better be less than the time or effort saved by the repeat of those saved keystrokes.&lt;/p&gt;
&lt;!--  l. 26  --&gt;
&lt;p class='indent'&gt;Here’s the thing. If you do something often enough your muscle memory will make it efficient over time. If you learn some shorter keystroke for an operation you repeat hundreds of times a day then you may slow a little at first but will quickly save time as your muscle memory improves. No need to spend time actively &lt;span class='ecti-1000'&gt;trying&lt;/span&gt; to learn it, you’re going to just by doing it. And if you don’t repeat it often in the course of your working day, then most likely you
didn’t need to save those keystrokes in the first place&lt;span class='footnote-mark'&gt;&lt;a href='#fn1x0' id='fn1x0-bk'&gt;&lt;sup class='textsuperscript'&gt;1&lt;/sup&gt;&lt;/a&gt;&lt;/span&gt;&lt;a id='x1-2f1'&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;!--  l. 28  --&gt;
&lt;p class='indent'&gt;When writing code the professional writes first for clarity and to make the code work (yeah, obvious I know). Only once the code is working will they worry about optimising. Arguing over whether a &lt;span class='inline-cmd'&gt;for&lt;/span&gt; loop is faster than a &lt;span class='inline-cmd'&gt;while&lt;/span&gt; loop in compiler &lt;span class='inline-cmd'&gt;xyz&lt;/span&gt; is something best left to amateurs (or compiler designers). Here’s the thing, we mere mortals can only know which parts of our code need to be
optimised once we can measure its performance. The ‘premature optimisation’ of code is a leading cause of shitty over-complex code. Some amateur thinks they know that accessing &lt;span class='inline-cmd'&gt;hash&lt;/span&gt; tables is microseconds slower than &lt;span class='inline-cmd'&gt;array&lt;/span&gt; accesses in some programming language, so they torture their code to use &lt;span class='inline-cmd'&gt;array&lt;/span&gt; even though the problem is better suited to &lt;span class='inline-cmd'&gt;hash&lt;/span&gt; tables. This takes them hours
longer to develop and debug, the code is a tangled mess but, ’hey! it runs 3 milliseconds faster than the &lt;span class='inline-cmd'&gt;hash&lt;/span&gt; version’. Great, but this code is invoked once every minute in real use scenarios. Was all that effort worth it? Is your dog shit code easy to maintain?&lt;/p&gt;
&lt;!--  l. 30  --&gt;
&lt;p class='indent'&gt;Contrast with the professional. Take the problem. Solve the problem in as clear a way as possible. Run the code. Does it work? Yes. Is it fast enough for the situation? Yes. Is it resource efficient enough? Yes. Job done, move on. Result? Clear, maintainable code that satisfies the problem and was quickly developed. It’s easier to debug and maintain because it is clearly written.&lt;/p&gt;
&lt;!--  l. 32  --&gt;
&lt;p class='indent'&gt;Suppose one of the conditions is not satisfied? If the clearly written code does not run fast enough? No problem. &lt;span class='ecti-1000'&gt;Now&lt;/span&gt; the professional starts looking at optimisation. First, the professional does not assume they know where the problem lies, they measure the scale of the problem. Use performance and coverage tools to figure out precisely where the code is being held up. Only then do they start changing things around. It may turn out that the &lt;span class='inline-cmd'&gt;hash&lt;/span&gt;/&lt;span class='inline-cmd'&gt;array&lt;/span&gt; access times are an insignificant factor. Let’s say we have a loop over some data that’s slowing our code. Can I do a simple test to avoid that loop all together in some circumstances? Have I got a loop within a loop (a very common costly process), can I unpack these loops or short-circuit the loops? If so, does this clear my performance bottleneck? If yes, then that’s the problem solved. If no, then maybe, just maybe, it’s time to use
&lt;span class='inline-cmd'&gt;array&lt;/span&gt; rather than &lt;span class='inline-cmd'&gt;hash&lt;/span&gt;&lt;span class='footnote-mark'&gt;&lt;a href='#fn2x0' id='fn2x0-bk'&gt;&lt;sup class='textsuperscript'&gt;2&lt;/sup&gt;&lt;/a&gt;&lt;/span&gt;&lt;a id='x1-3f2'&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;!--  l. 34  --&gt;
&lt;p class='indent'&gt;At this point the amateur may be feeling very smug because the professional has had to finally admit that ’yes, arrays are an optimization in this case’, but in truth the professional approach will produce better code overall and situations requiring this sort of fine optimisation are the exception rather than the rule. In over 30 years of working IT I can count on the fingers of one hand the times that I’ve had to perform low-level optimisations. Most optimisations have been less obvious
but much grosser (like realising that maintaining a larger session pool, or unpacking nested loops, will solve a problem, rather than fiddling with shaving microseconds of my code&lt;span class='footnote-mark'&gt;&lt;a href='#fn3x0' id='fn3x0-bk'&gt;&lt;sup class='textsuperscript'&gt;3&lt;/sup&gt;&lt;/a&gt;&lt;/span&gt;&lt;a id='x1-4f3'&gt;&lt;/a&gt;).&lt;/p&gt;
&lt;!--  l. 36  --&gt;
&lt;p class='indent'&gt;Does this mean we should avoid learning more efficient ways of working? No, of course not. Just don’t waste time fussing the detail too early.&lt;/p&gt;
&lt;div class='footnotes'&gt;&lt;!--  l. 26  --&gt;
&lt;p class='indent'&gt;&lt;span class='footnote-mark'&gt;&lt;a href='#fn1x0-bk' id='fn1x0'&gt;&lt;sup class='textsuperscript'&gt;1&lt;/sup&gt;&lt;/a&gt;&lt;/span&gt;&lt;span class='ecrm-0800'&gt;With regards to ViM, learning the general pattern&lt;/span&gt; &lt;span class='inline-cmd'&gt;&lt;span class='ecrm-0800'&gt;command&lt;/span&gt;&lt;span class='tcrm-0800'&gt;→&lt;/span&gt;&lt;span class='ecrm-0800'&gt;movement&lt;/span&gt;&lt;/span&gt; &lt;span class='ecrm-0800'&gt;is&lt;/span&gt; &lt;span class='ecrm-0800'&gt;definitely useful, as is learning the how to move about ViM. Trust me, you’ll be doing this a&lt;/span&gt;
&lt;span class='ecrm-0800'&gt;lot so forcing yourself to, for example, skip to last line on screen with&lt;/span&gt; &lt;span class='inline-cmd'&gt;&lt;span class='ecrm-0800'&gt;L&lt;/span&gt;&lt;/span&gt; &lt;span class='ecrm-0800'&gt;(rather then&lt;/span&gt; &lt;span class='ecrm-0800'&gt;repeatedly mashing&lt;/span&gt; &lt;span class='inline-cmd'&gt;&lt;span class='ecrm-0800'&gt;j&lt;/span&gt;&lt;/span&gt;&lt;span class='ecrm-0800'&gt;) is going to stick real quick once you’ve overcome the short-term&lt;/span&gt; &lt;span class='ecrm-0800'&gt;slowdown.&lt;/span&gt;&lt;/p&gt;
&lt;!--  l. 32  --&gt;
&lt;p class='indent'&gt;&lt;span class='footnote-mark'&gt;&lt;a href='#fn2x0-bk' id='fn2x0'&gt;&lt;sup class='textsuperscript'&gt;2&lt;/sup&gt;&lt;/a&gt;&lt;/span&gt;&lt;span class='ecrm-0800'&gt;When making this sort of change leave a comment detailing&lt;/span&gt; &lt;span class='ecti-0800'&gt;why&lt;/span&gt; &lt;span class='ecrm-0800'&gt;you did it. This is one of&lt;/span&gt; &lt;span class='ecrm-0800'&gt;the circumstances in which extended comments are invaluable.&lt;/span&gt;&lt;/p&gt;
&lt;!--  l. 34  --&gt;
&lt;p class='indent'&gt;&lt;span class='footnote-mark'&gt;&lt;a href='#fn3x0-bk' id='fn3x0'&gt;&lt;sup class='textsuperscript'&gt;3&lt;/sup&gt;&lt;/a&gt;&lt;/span&gt;&lt;span class='ecrm-0800'&gt;Again, don’t get the idea you should simply throw resources at a problem! That sort of&lt;/span&gt; &lt;span class='ecrm-0800'&gt;thinking results in bloated shitty systems too. It’s about knowing where best to invest your&lt;/span&gt; &lt;span class='ecrm-0800'&gt;resources—especially you time.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;</content><author><name>Mark Bools</name><email>mark@saltyvagrant.com</email></author><category term="Opinion" /><category term="Practices" /><category term="AvP" /><summary type="html">TL;DR What distinguishes an amateur from a professional? Let’s consider optimisation. (Obviously much of this is opinion.)</summary></entry><entry><title type="html">Fences and Ambulances</title><link href="https://saltyvagrant.com/2021/01/29/fences-and-ambulances.html" rel="alternate" type="text/html" title="Fences and Ambulances" /><published>2021-01-29T00:00:00+00:00</published><updated>2021-01-29T00:00:00+00:00</updated><id>https://saltyvagrant.com/2021/01/29/fences-and-ambulances</id><content type="html" xml:base="https://saltyvagrant.com/2021/01/29/fences-and-ambulances.html">&lt;div class='abstract'&gt;&lt;span class='ecbx-0900'&gt;TL;DR&lt;/span&gt; &lt;span class='ecrm-0900'&gt;Prevention is better than cure, but we need both available&lt;/span&gt; &lt;span class='ecrm-0900'&gt;when managing complex IT systems.&lt;/span&gt;
&lt;hr /&gt;&lt;/div&gt;
&lt;!--  more  --&gt;
&lt;!--  l. 13  --&gt;
&lt;p class='indent'&gt;When you live near a cliff edge it is common-sense to build a fence along the edge to prevent people falling over that cliff. That said, it is also worthwhile having ambulances available to take those who do fall to hospital.&lt;/p&gt;
&lt;!--  l. 15  --&gt;
&lt;p class='indent'&gt;Fences are always a compromise; too low and they may as well not exist, too high and the block the view. Also, some people are insistent on climbing over fences and fences inevitably fall into disrepair over time.&lt;/p&gt;
&lt;!--  l. 17  --&gt;
&lt;p class='indent'&gt;What am I blathering on about fences for?&lt;/p&gt;
&lt;!--  l. 19  --&gt;
&lt;p class='indent'&gt;Consider your IT system, it is likely you have some proactive protections in place. Limiting access to production systems, using encryption, setting up firewalls, and so forth. These are your fences.&lt;/p&gt;
&lt;!--  l. 21  --&gt;
&lt;p class='indent'&gt;I would also wager that you have system failures too. When your system fails you have process and procedure for recovering the system back to an operational state. These reactive recovery process is your ambulance fleet.&lt;/p&gt;</content><author><name>Mark Bools</name><email>mark@saltyvagrant.com</email></author><summary type="html">TL;DR Prevention is better than cure, but we need both available when managing complex IT systems.</summary></entry><entry><title type="html">Removing a Locked Virtualbox VM</title><link href="https://saltyvagrant.com/2021/01/18/removing-locked-virtualbox-vms.html" rel="alternate" type="text/html" title="Removing a Locked Virtualbox VM" /><published>2021-01-18T00:00:00+00:00</published><updated>2021-01-18T00:00:00+00:00</updated><id>https://saltyvagrant.com/2021/01/18/removing-locked-virtualbox-vms</id><content type="html" xml:base="https://saltyvagrant.com/2021/01/18/removing-locked-virtualbox-vms.html">&lt;!--  l. 5  --&gt;
&lt;p class='noindent'&gt;&lt;/p&gt;
&lt;div class='abstract'&gt;&lt;span class='ecbx-0900'&gt;TL;DR&lt;/span&gt; &lt;span class='ecrm-0900'&gt;Occasionally you will get a Virtualbox VM into a locked state&lt;/span&gt; &lt;span class='ecrm-0900'&gt;and this will prevent it being deleted. Attempts to delete or unregister&lt;/span&gt; &lt;span class='ecrm-0900'&gt;the VM result in the error&lt;/span&gt; &lt;span class='inline-cmd'&gt;&lt;span class='ecrm-0900'&gt;Stderr: VBoxManage: error: The machine&lt;/span&gt; &lt;span class='ecrm-0900'&gt;’centos64_c6402_1454036461345_59755’ is already locked for a session&lt;/span&gt;
&lt;span class='ecrm-0900'&gt;(or being unlocked)&lt;/span&gt;&lt;/span&gt;&lt;span class='ecrm-0900'&gt;. This article describes how to resolve this problem.&lt;/span&gt;
&lt;hr /&gt;&lt;/div&gt;
&lt;!--  more  --&gt;
&lt;!--  l. 15  --&gt;
&lt;p class='indent'&gt;&lt;/p&gt;
&lt;!--  l. 18  --&gt;
&lt;p class='indent'&gt;The Virtualbox virtual machine (VM) you are trying to remove or unregister is ‘locked’ producing an error like the folowing.&lt;/p&gt;
&lt;pre class='fancyvrb' id='fancyvrb1'&gt;&lt;a id='x1-6r1'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;1&lt;/span&gt;&lt;span class='ectt-1000'&gt;Stderr: VBoxManage: error: The machine &lt;/span&gt;&lt;span class='textcolor-ba2121'&gt;&lt;span class='tctt-1000'&gt;'&lt;/span&gt;&lt;span class='ectt-1000'&gt;centos64_c6402_1454036461345_59755&lt;/span&gt;&lt;span class='tctt-1000'&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; is already locked &lt;/span&gt;&lt;span class='textcolor-007f00'&gt;&lt;span class='ectt-1000'&gt;for&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; a session &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;or being unlocked&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;)&lt;/span&gt;&lt;/span&gt; 
&lt;a id='x1-8r2'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;2&lt;/span&gt;&lt;span class='ectt-1000'&gt;VBoxManage: error: Details: code VBOX_E_INVALID_OBJECT_STATE &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;0x80bb0007&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;, component MachineWrap, interface IMachine, callee nsISupports&lt;/span&gt; 
&lt;a id='x1-10r3'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;3&lt;/span&gt;&lt;span class='ectt-1000'&gt;VBoxManage: error: Context: &lt;/span&gt;&lt;span class='textcolor-ba2121'&gt;&lt;span class='ectt-1000'&gt;&quot;LockMachine(a-&amp;gt;session, LockType_Write)&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; at line &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;493&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; of file VBoxManageModifyVM.cpp&lt;/span&gt;&lt;/pre&gt;
&lt;!--  l. 26  --&gt;
&lt;p class='indent'&gt;The simplest way I know the ‘unlock’ this sort of VM is using an ‘&lt;span class='inline-cmd'&gt;emergencystop&lt;/span&gt;.&lt;/p&gt;
&lt;pre class='fancyvrb' id='fancyvrb2'&gt;&lt;a id='x1-13r1'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;1&lt;/span&gt;&lt;span class='ectt-1000'&gt;VBoxManage startvm &amp;lt;vm-uuid&amp;gt; --type emergencystop&lt;/span&gt;&lt;/pre&gt;
&lt;!--  l. 32  --&gt;
&lt;p class='indent'&gt;Where &lt;span class='inline-cmd'&gt;&amp;lt;vm-uuid&amp;gt;&lt;/span&gt; is found using &lt;span class='inline-cmd'&gt;VMoxManage list vms&lt;/span&gt; (the UUID being the long collection of characters between the &lt;span class='inline-cmd'&gt;{}&lt;/span&gt; at the end of each line).&lt;/p&gt;
&lt;pre class='fancyvrb' id='fancyvrb3'&gt;&lt;a id='x1-16r1'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;1&lt;/span&gt;&lt;span class='ectt-1000'&gt;VBoxManage list vms&lt;/span&gt;&lt;/pre&gt;
&lt;pre class='fancyvrb' id='fancyvrb4'&gt;&lt;a id='x1-21r1'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;1&lt;/span&gt;&lt;span class='textcolor-ba2121'&gt;&lt;span class='ectt-1000'&gt;&quot;Whonix-Gateway&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;{&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;d89a93c5-d0f3-48ef-9e5c-bf0df89931f1&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;}&lt;/span&gt;&lt;/span&gt; 
&lt;a id='x1-23r2'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;2&lt;/span&gt;&lt;span class='textcolor-ba2121'&gt;&lt;span class='ectt-1000'&gt;&quot;Whonix-Workstation&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;{&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;05647ae6-792c-4caf-be5e-1508c6d012cf&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;}&lt;/span&gt;&lt;/span&gt; 
&lt;a id='x1-25r3'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;3&lt;/span&gt;&lt;span class='textcolor-ba2121'&gt;&lt;span class='ectt-1000'&gt;&quot;Buscador-1.2(3-10-18)&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;{&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;c44145ec-5a71-44b2-a6cb-c590ab92d273&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;!--  l. 44  --&gt;
&lt;p class='indent'&gt;Once the VM is unlocked you can remove it as usual.&lt;/p&gt;
&lt;pre class='fancyvrb' id='fancyvrb5'&gt;&lt;a id='x1-28r1'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;1&lt;/span&gt;&lt;span class='ectt-1000'&gt;VBoxManage unregistervm --delete &amp;lt;vm-uuid&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;!--  l. 50  --&gt;
&lt;p class='indent'&gt;Or simply unregister it if you have deleted the VM files already.&lt;/p&gt;
&lt;pre class='fancyvrb' id='fancyvrb6'&gt;&lt;a id='x1-31r1'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;1&lt;/span&gt;&lt;span class='ectt-1000'&gt;VBoxManage unregistervm &amp;lt;vm-uuid&amp;gt;&lt;/span&gt;&lt;/pre&gt;</content><author><name>Mark Bools</name><email>mark@saltyvagrant.com</email></author><category term="Virtualbox" /><summary type="html">TL;DR Occasionally you will get a Virtualbox VM into a locked state and this will prevent it being deleted. Attempts to delete or unregister the VM result in the error Stderr: VBoxManage: error: The machine ’centos64_c6402_1454036461345_59755’ is already locked for a session (or being unlocked). This article describes how to resolve this problem.</summary></entry><entry><title type="html">sudo users</title><link href="https://saltyvagrant.com/2020/12/10/sudo-users.html" rel="alternate" type="text/html" title="sudo users" /><published>2020-12-10T00:00:00+00:00</published><updated>2020-12-10T00:00:00+00:00</updated><id>https://saltyvagrant.com/2020/12/10/sudo-users</id><content type="html" xml:base="https://saltyvagrant.com/2020/12/10/sudo-users.html">&lt;div class='abstract'&gt;&lt;span class='ecbx-0900'&gt;TL;DR&lt;/span&gt; &lt;span class='ecrm-0900'&gt;Protecting your system from accidental or malicious change&lt;/span&gt; &lt;span class='ecrm-0900'&gt;is made simpler by allowing users only limited access. This especially&lt;/span&gt; &lt;span class='ecrm-0900'&gt;means limiting users who have&lt;/span&gt; &lt;span class='inline-cmd'&gt;&lt;span class='ecrm-0900'&gt;root&lt;/span&gt;&lt;/span&gt; &lt;span class='ecrm-0900'&gt;or ‘superuser’ access as these users&lt;/span&gt; &lt;span class='ecrm-0900'&gt;have effectively unlimited power. When
it is necessary for a user to have&lt;/span&gt; &lt;span class='ecrm-0900'&gt;this access it is best that they have a normal (unprivileged) account for&lt;/span&gt; &lt;span class='ecrm-0900'&gt;day-to-day activities with the ability to temporarily promote themselves&lt;/span&gt; &lt;span class='ecrm-0900'&gt;to ‘superuser’ to run commands that require this elevated access.&lt;/span&gt;
&lt;hr /&gt;&lt;/div&gt;
&lt;!--  more  --&gt;
&lt;!--  l. 14  --&gt;
&lt;p class='indent'&gt;&lt;/p&gt;
&lt;!--  l. 17  --&gt;
&lt;p class='indent'&gt;First, some basics of Linux access control.&lt;/p&gt;
&lt;!--  l. 19  --&gt;
&lt;p class='indent'&gt;Linux accounts all have two basic identities that the operating system uses to control access to facilities like which files the account holder can access and what programs the user can execute; the user id (&lt;span class='inline-cmd'&gt;uid&lt;/span&gt;) and the group id (&lt;span class='inline-cmd'&gt;gid&lt;/span&gt;). You can easily see the &lt;span class='inline-cmd'&gt;uid&lt;/span&gt; and &lt;span class='inline-cmd'&gt;gid&lt;/span&gt; for an account using the &lt;span class='inline-cmd'&gt;id&lt;/span&gt; command.&lt;/p&gt;
&lt;pre class='fancyvrb' id='fancyvrb1'&gt;&lt;a id='x1-4r1'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;1&lt;/span&gt;&lt;span class='ectt-1000'&gt;id vagrant&lt;/span&gt;&lt;/pre&gt;
&lt;!--  l. 25  --&gt;
&lt;p class='indent'&gt;This will show the &lt;span class='inline-cmd'&gt;vagrant&lt;/span&gt; account’s current &lt;span class='inline-cmd'&gt;uid&lt;/span&gt; and &lt;span class='inline-cmd'&gt;gid&lt;/span&gt; along with a list of ‘groups’ to which that account belongs.&lt;/p&gt;
&lt;pre class='fancyvrb' id='fancyvrb2'&gt;&lt;a id='x1-7r1'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;1&lt;/span&gt;&lt;span class='textcolor-19167c'&gt;&lt;span class='ectt-1000'&gt;uid&lt;/span&gt;&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;=1000(&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;vagrant&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; &lt;/span&gt;&lt;span class='textcolor-19167c'&gt;&lt;span class='ectt-1000'&gt;gid&lt;/span&gt;&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;=1000(&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;vagrant&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; &lt;/span&gt;&lt;span class='textcolor-19167c'&gt;&lt;span class='ectt-1000'&gt;groups&lt;/span&gt;&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;=1000(&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;vagrant&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;,24&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;cdrom&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;,25&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;floppy&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;,27&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;sudo&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;,29&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;audio&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;,30&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;dip&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;,44&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;video&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;,46&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;plugdev&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;,109&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;netdev&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;,111&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;bluetooth&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;,997&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;docker&lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;!--  l. 31  --&gt;
&lt;p class='indent'&gt;Issuing the command &lt;span class='inline-cmd'&gt;id&lt;/span&gt; without specifing a username will return these details for the current account.&lt;/p&gt;
&lt;!--  l. 33  --&gt;
&lt;p class='indent'&gt;What does this all mean?&lt;/p&gt;
&lt;!--  l. 35  --&gt;
&lt;p class='indent'&gt;Access to files is specified on three axes; &lt;span class='inline-cmd'&gt;user&lt;/span&gt;, &lt;span class='inline-cmd'&gt;group&lt;/span&gt;, and &lt;span class='inline-cmd'&gt;other&lt;/span&gt;. For each axis we can specify &lt;span class='inline-cmd'&gt;read&lt;/span&gt; access, &lt;span class='inline-cmd'&gt;write&lt;/span&gt; access, and &lt;span class='inline-cmd'&gt;execute&lt;/span&gt; access. All of this information can be seen using the &lt;span class='inline-cmd'&gt;ls&lt;/span&gt; command.&lt;/p&gt;
&lt;pre class='fancyvrb' id='fancyvrb3'&gt;&lt;a id='x1-10r1'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;1&lt;/span&gt;&lt;span class='ectt-1000'&gt;ls -l&lt;/span&gt;&lt;/pre&gt;
&lt;pre class='fancyvrb' id='fancyvrb4'&gt;&lt;a id='x1-29r1'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;1&lt;/span&gt;&lt;span class='ectt-1000'&gt;total &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;64&lt;/span&gt;&lt;/span&gt; 
&lt;a id='x1-31r2'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;2&lt;/span&gt;&lt;span class='ectt-1000'&gt;drwxr-xr-x  &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;7&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; vagrant vagrant &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;4096&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; Nov &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;18&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;15&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;:33 .&lt;/span&gt; 
&lt;a id='x1-33r3'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;3&lt;/span&gt;&lt;span class='ectt-1000'&gt;drwxr-xr-x &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;37&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; vagrant vagrant &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;4096&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; Dec  &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;3&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;09&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;:01 ..&lt;/span&gt; 
&lt;a id='x1-35r4'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;4&lt;/span&gt;&lt;span class='ectt-1000'&gt;-rw-r--r--  &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;1&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; vagrant vagrant  &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;419&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; Nov &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;18&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;09&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;:23 &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;404&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;.html&lt;/span&gt; 
&lt;a id='x1-37r5'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;5&lt;/span&gt;&lt;span class='ectt-1000'&gt;-rw-r--r--  &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;1&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; vagrant vagrant  &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;412&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; Nov &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;18&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;09&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;:23 about.markdown&lt;/span&gt; 
&lt;a id='x1-39r6'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;6&lt;/span&gt;&lt;span class='ectt-1000'&gt;drwxr-xr-x  &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;3&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; vagrant vagrant &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;4096&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; Nov &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;18&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;09&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;:23 assets&lt;/span&gt; 
&lt;a id='x1-41r7'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;7&lt;/span&gt;&lt;span class='ectt-1000'&gt;-rw-r--r--  &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;1&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; vagrant vagrant  &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;672&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; Nov &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;18&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;09&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;:23 books.markdown&lt;/span&gt; 
&lt;a id='x1-43r8'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;8&lt;/span&gt;&lt;span class='ectt-1000'&gt;-rw-r--r--  &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;1&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; vagrant vagrant &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;2352&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; Nov &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;18&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;09&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;:23 _config.yml&lt;/span&gt; 
&lt;a id='x1-45r9'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;9&lt;/span&gt;&lt;span class='ectt-1000'&gt;-rw-r--r--  &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;1&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; vagrant vagrant &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;1131&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; Nov &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;18&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;09&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;:23 Gemfile&lt;/span&gt; 
&lt;a id='x1-47r10'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;10&lt;/span&gt;&lt;span class='ectt-1000'&gt;-rw-r--r--  &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;1&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; vagrant vagrant &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;1869&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; Nov &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;18&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;09&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;:23 Gemfile.lock&lt;/span&gt; 
&lt;a id='x1-49r11'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;11&lt;/span&gt;&lt;span class='ectt-1000'&gt;drwxr-xr-x  &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;8&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; vagrant vagrant &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;4096&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; Nov &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;18&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;15&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;:33 .git&lt;/span&gt; 
&lt;a id='x1-51r12'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;12&lt;/span&gt;&lt;span class='ectt-1000'&gt;-rw-r--r--  &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;1&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; vagrant vagrant   &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;56&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; Oct &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;10&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;13&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;:36 .gitignore&lt;/span&gt; 
&lt;a id='x1-53r13'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;13&lt;/span&gt;&lt;span class='ectt-1000'&gt;drwxr-xr-x  &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;2&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; vagrant vagrant &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;4096&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; Nov &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;18&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;09&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;:23 _includes&lt;/span&gt; 
&lt;a id='x1-55r14'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;14&lt;/span&gt;&lt;span class='ectt-1000'&gt;-rw-r--r--  &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;1&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; vagrant vagrant  &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;178&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; Nov &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;18&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;09&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;:23 index.markdown&lt;/span&gt; 
&lt;a id='x1-57r15'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;15&lt;/span&gt;&lt;span class='ectt-1000'&gt;drwxr-xr-x  &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;3&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; vagrant vagrant &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;4096&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; Oct &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;10&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;13&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;:41 .jekyll-cache&lt;/span&gt; 
&lt;a id='x1-59r16'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;16&lt;/span&gt;&lt;span class='ectt-1000'&gt;-rw-r--r--  &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;1&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; vagrant vagrant  &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;629&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; Nov &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;18&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;09&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;:23 saltyvagrant.markdown&lt;/span&gt; 
&lt;a id='x1-61r17'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;17&lt;/span&gt;&lt;span class='ectt-1000'&gt;drwxr-xr-x  &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;4&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; vagrant vagrant &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;4096&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; Nov &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;18&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;09&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;:23 _sass§&lt;/span&gt;&lt;/pre&gt;
&lt;!--  l. 61  --&gt;
&lt;p class='indent'&gt;Looking at line 3 we see that the &lt;span class='inline-cmd'&gt;404.html&lt;/span&gt; file has its access ‘mode’ set to &lt;span class='inline-cmd'&gt;-rw-r–r–&lt;/span&gt;. We read the first character as a special indicator (the first, in this example &lt;span class='inline-cmd'&gt;-&lt;/span&gt;, meaning ‘not set’). The remaining nine indicators are read in groups of three. Each group contains; &lt;span class='inline-cmd'&gt;r&lt;/span&gt; read, &lt;span class='inline-cmd'&gt;w&lt;/span&gt; write, &lt;span class='inline-cmd'&gt;x&lt;/span&gt; execute, or
&lt;span class='inline-cmd'&gt;-&lt;/span&gt; for ‘not set’. The three groups represent &lt;span class='inline-cmd'&gt;owner&lt;/span&gt;, &lt;span class='inline-cmd'&gt;group&lt;/span&gt;, and &lt;span class='inline-cmd'&gt;other&lt;/span&gt;.&lt;/p&gt;
&lt;!--  l. 63  --&gt;
&lt;p class='indent'&gt;Reading the &lt;span class='inline-cmd'&gt;404.html&lt;/span&gt; file mode (&lt;span class='inline-cmd'&gt;-rw-r–r–&lt;/span&gt;) we see; special is not set (&lt;span class='inline-cmd'&gt;-&lt;/span&gt;), user (&lt;span class='inline-cmd'&gt;vagrant&lt;/span&gt; as indicated by the entry in the third column of output) can read and write but not execute (&lt;span class='inline-cmd'&gt;rw-&lt;/span&gt;), Any account in the group (&lt;span class='inline-cmd'&gt;vagrant&lt;/span&gt; as indicated by the entry in the fourth column of output) can read this file but
can neither write not execute it (&lt;span class='inline-cmd'&gt;r–&lt;/span&gt;). The final three entries show that any account on the machine can read but neither write nor execute it (&lt;span class='inline-cmd'&gt;r–&lt;/span&gt;).&lt;/p&gt;
&lt;!--  l. 65  --&gt;
&lt;p class='indent'&gt;Looking at line 5 we see that &lt;span class='inline-cmd'&gt;assets&lt;/span&gt; is a directory, indicated by the &lt;span class='inline-cmd'&gt;d&lt;/span&gt; special indicator (the first character on the line). User &lt;span class='inline-cmd'&gt;vagrant&lt;/span&gt; can read, write, and execute the &lt;span class='inline-cmd'&gt;assets&lt;/span&gt; directory. What does ‘execute’ mean on a directory? Any account with execute access &lt;span class='inline-cmd'&gt;x&lt;/span&gt; can list the directory content (in this example any account can list
the &lt;span class='inline-cmd'&gt;assets&lt;/span&gt; directory content as indicated by the &lt;span class='inline-cmd'&gt;x&lt;/span&gt; in the final position).&lt;/p&gt;
&lt;!--  l. 67  --&gt;
&lt;p class='indent'&gt;Under normal circumstances only the account &lt;span class='inline-cmd'&gt;vagrant&lt;/span&gt; would be able to add a file to the &lt;span class='inline-cmd'&gt;assets&lt;/span&gt; directry or make changes (write) to the &lt;span class='inline-cmd'&gt;404.html&lt;/span&gt; file. Superusers however are above these restrictions and are able to do aything they please to these files.&lt;/p&gt;
&lt;!--  l. 69  --&gt;
&lt;p class='indent'&gt;Who are superusers?&lt;/p&gt;
&lt;!--  l. 71  --&gt;
&lt;p class='indent'&gt;The special &lt;span class='inline-cmd'&gt;root&lt;/span&gt; account is always a superuser. Generally it is good practice though to prevent direct login access to the &lt;span class='inline-cmd'&gt;root&lt;/span&gt; account. Instead we provide non-privileged accounts with a way to run privileged commands but only when some special action is taken. This need to take some special action to run commands as a superuser will (hopefully) reduce the potential for mistakes.&lt;/p&gt;
&lt;!--  l. 73  --&gt;
&lt;p class='indent'&gt;The special action required is called &lt;span class='inline-cmd'&gt;sudo&lt;/span&gt;, short for superuser do. This is a special command, normally used as a prefix to whatever command we want to run with superuser privilege.&lt;/p&gt;
&lt;!--  l. 75  --&gt;
&lt;p class='indent'&gt;Why is it bad practice to allow direct login access to &lt;span class='inline-cmd'&gt;root&lt;/span&gt; but instead use &lt;span class='inline-cmd'&gt;sudo&lt;/span&gt;? Four reasons;&lt;/p&gt;
&lt;ol class='enumerate1'&gt;
&lt;li class='enumerate' id='x1-63x1'&gt;Using &lt;span class='inline-cmd'&gt;sudo&lt;/span&gt; requires an explicit action to perform privileged actions (actions that may have significant effects on your system).&lt;/li&gt;
&lt;li class='enumerate' id='x1-65x2'&gt;All &lt;span class='inline-cmd'&gt;sudo&lt;/span&gt; actions are logged, making it simpler to find who actually performed each privileged action.&lt;/li&gt;
&lt;li class='enumerate' id='x1-67x3'&gt;&lt;span class='inline-cmd'&gt;sudo&lt;/span&gt; actions can be controlled such that the account may run only certain commands with superuser rights.&lt;/li&gt;
&lt;li class='enumerate' id='x1-69x4'&gt;The right to run &lt;span class='inline-cmd'&gt;sudo&lt;/span&gt; commands can be granted and revoked very simply.&lt;/li&gt;
&lt;/ol&gt;
&lt;!--  l. 84  --&gt;
&lt;p class='indent'&gt;Logged in to the non-privileged account &lt;span class='inline-cmd'&gt;vagrant&lt;/span&gt; we can look at &lt;span class='inline-cmd'&gt;ls -l /etc/hosts&lt;/span&gt;, the local hosts file.&lt;/p&gt;
&lt;pre class='fancyvrb' id='fancyvrb5'&gt;&lt;a id='x1-72r1'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;1&lt;/span&gt;&lt;span class='ectt-1000'&gt;-rw-r--r-- &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;1&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; root root &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;254&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; Oct &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;14&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt; &lt;/span&gt;&lt;span class='textcolor-656565'&gt;&lt;span class='ectt-1000'&gt;13&lt;/span&gt;&lt;/span&gt;&lt;span class='ectt-1000'&gt;:39 /etc/hosts&lt;/span&gt;&lt;/pre&gt;
&lt;!--  l. 90  --&gt;
&lt;p class='indent'&gt;This tells us that only the &lt;span class='inline-cmd'&gt;root&lt;/span&gt; user has write access to this file. Suppose the &lt;span class='inline-cmd'&gt;vagrant&lt;/span&gt; user needs to edit this file.&lt;/p&gt;
&lt;!--  l. 92  --&gt;
&lt;p class='indent'&gt;First we need to tell the operating system that &lt;span class='inline-cmd'&gt;vagrant&lt;/span&gt; is allowed to run elevated commands using &lt;span class='inline-cmd'&gt;sudo&lt;/span&gt;. This is very simple, the &lt;span class='inline-cmd'&gt;vagrant&lt;/span&gt; account must be added to the &lt;span class='inline-cmd'&gt;sudo&lt;/span&gt; &lt;span class='ecti-1000'&gt;group&lt;/span&gt;. Typically, any account that is a member of this &lt;span class='inline-cmd'&gt;sudo&lt;/span&gt; group is permitted to run the &lt;span class='inline-cmd'&gt;sudo&lt;/span&gt;
command, and by extension is allowed to run commands as a superuser. I say ‘typically’ because the &lt;span class='inline-cmd'&gt;sudo&lt;/span&gt; facility allows much more subtle configuration of what each account or group may do. We could, for example, create a group &lt;span class='inline-cmd'&gt;reboot&lt;/span&gt; that would allow member of the group to issue a command to reboot the server but have access to no other privileged operation. Similarly, we could change the &lt;span class='inline-cmd'&gt;sudo&lt;/span&gt; group to allow
limited access, but as I say, it is more common to leave &lt;span class='inline-cmd'&gt;sudo&lt;/span&gt; as all powerful and create other more specialised groups as required.&lt;/p&gt;
&lt;!--  l. 94  --&gt;
&lt;p class='indent'&gt;As it happens our &lt;span class='inline-cmd'&gt;vagrant&lt;/span&gt; account is already a member of the &lt;span class='inline-cmd'&gt;sudo&lt;/span&gt; group (we can see this in the output of the &lt;span class='inline-cmd'&gt;id vagrant&lt;/span&gt; command shown above).&lt;/p&gt;
&lt;!--  l. 96  --&gt;
&lt;p class='indent'&gt;If the &lt;span class='inline-cmd'&gt;vagrant&lt;/span&gt; account was not already a member of this group we could add it using the command &lt;span class='inline-cmd'&gt;usermod -g -G sudo vagrant&lt;/span&gt;. As you might expect this command requires superuser privilege (otherwise any account would be able to add itself to the &lt;span class='inline-cmd'&gt;sudo&lt;/span&gt; group, making a mockery of our security). So the command we want is &lt;span class='inline-cmd'&gt;sudo usermod -g -G sudo vagrant&lt;/span&gt; run by an
account that is already a member of the &lt;span class='inline-cmd'&gt;sudo&lt;/span&gt; group (alternatively we could use the &lt;span class='inline-cmd'&gt;root&lt;/span&gt; account without using &lt;span class='inline-cmd'&gt;sudo&lt;/span&gt; but as we said above, direct login access to the &lt;span class='inline-cmd'&gt;root&lt;/span&gt; account is to be avoided). The obvious point here being that when we initially set up our system to use &lt;span class='inline-cmd'&gt;sudo&lt;/span&gt; we must have at least one account as a member of the &lt;span class='inline-cmd'&gt;sudo&lt;/span&gt; group.&lt;/p&gt;
&lt;pre class='fancyvrb' id='fancyvrb6'&gt;&lt;a id='x1-75r1'&gt;&lt;/a&gt;&lt;span class='ecrm-0600'&gt;1&lt;/span&gt;&lt;span class='ectt-1000'&gt;sudo vi /etc/hosts&lt;/span&gt;&lt;/pre&gt;
&lt;!--  l. 102  --&gt;
&lt;p class='indent'&gt;Prefixing the edit comand with &lt;span class='inline-cmd'&gt;sudo&lt;/span&gt; allows the account to edit the file regardless of the normal access rights on the file.&lt;/p&gt;</content><author><name>Mark Bools</name><email>mark@saltyvagrant.com</email></author><category term="Security" /><summary type="html">TL;DR Protecting your system from accidental or malicious change is made simpler by allowing users only limited access. This especially means limiting users who have root or ‘superuser’ access as these users have effectively unlimited power. When it is necessary for a user to have this access it is best that they have a normal (unprivileged) account for day-to-day activities with the ability to temporarily promote themselves to ‘superuser’ to run commands that require this elevated access.</summary></entry></feed>