So, like many great stories, the story of Git LFS begins in Paris. It was the 8th of April 2015, and a bunch of engineers were gathered for the annual Git contributors summit where all of the thought leaders in the Git community get together and talk about how they're going to develop everyone's favorite distributed version control system for the next 12 months.  At one point, Nicola Pellucci and John Garcia, a couple of Atlassian devs attached to Bitbucket, were chatting to Rick Olson from GitHub. And Nick said to Rick, hey, you guys at GitHub might be interested in this new thing that we've been building. Atlassian have developed an extension to Git that solves the problem that Git has with tracking large binary content. So we've built this extension in Go, and we're planning on announcing it at our track session during Git merge tomorrow. And Rick from GitHub said, it's kind of funny. You might be interested in this. At GitHub, we've also been interested in this problem that Git has with tracking large binary files. So we've built an extension to Git in Go, and we're planning on announcing it at Git merge tomorrow in our track session, which happens to be immediately before yours. And Nick went, what? That's a picture of James, what, by the way? And Rick went, it sounds like we've kind of both solved the same problem. So what do you call yours? And this is where it gets really weird. And Nick said, well, we call ours Git lob, after long objects like you might find in a database, because we're trying to figure out how to store this large content in a better way. And Rick said, well, OK, that's really weird, because we also picked a three-letter acronym starting with L, Git LFS, for large file storage. And after a bit back and forth between the two companies and the conversations that I went over a couple of months after that, we decided to ultimately mothball an open source Git lob and start contributing to the Git LFS project instead. Now, fortunately, in an interesting example of parallel evolution, both Git lob and Git LFS were designed in pretty similar ways. They both used exactly the same Git extension points, and they were both built in Go. So our developers managed to port some of the features that we had built into lob that didn't yet exist in LFS over into the other project, which means now we have one project, which is fantastic because we haven't fragmented the community. One of the really nice things about Git is it's a really portable data format, and now that there are a few different Git hosting providers out there, it's nice that you can still migrate your repositories from one to the other if you so choose. Now, Git LFS is really exciting as a piece of technology in itself, but what's more exciting for me is that it means that literally every team in the world can start using distributed version control. Now, there was a subset of software teams out there who was stuck on centralized version control because they couldn't move to Git purely because it was distributed. If you're working on a team that's developing a game, for example, or if you're a researcher that needs to version huge data sets alongside their code, then it's really tricky to use Git because as a distributed version control system, you have to copy the entire repository history locally whenever you want to do something with it. Unfortunately, Git LFS kind of breaks this distributed part of Git, but only for large files, and I'll go a little bit more into detail about how that works in a couple of minutes.  So this means that game designers with large assets, researchers with data sets, web developers with rich media that they want to version alongside their HTML source code, or even engineers who want to do things like build functional tests and check in snapshots of databases into their Git repositories can do that now. It opens up a huge number of convenient ways to version control assets that were just too big for Git in the past. So there's four broad things I want to cover today. First, I want to talk a little bit about why Git doesn't handle tracking large files very well. Then we'll look at how Git LFS solves this problem. And then I'll give you some tips for converting your existing Git repositories over to use Git LFS if you're already tracking large binaries in there. And then finally, I'll give you some tips for using Git LFS in a team context, because most software these days is built in some kind of team.  Just for reference, how many people here are already using Git? OK, almost everybody. Fantastic. So I can probably breeze through this section fairly quickly. So in Git, you have a master branch, typically. This is kind of the equivalent of a trunk branch and subversion, or a default branch in Mercurial. And what this branch really is, is a lightweight pointer to a commit sitting somewhere in your repository history. And branches are so lightweight in Git, because literally all it is is one of these references. Inside your .git directory, which contains all of your repository data, there's a refs directory, which contains all of your branches and tags and other pointers pointing at different commits in your Git graph. Now, the master branch is literally just a file containing a scary-looking 40-byte hexadecimal hash. And what this hash is actually what Git uses for a commit identifier. And it tells you not only where that commit is sitting on disk, but it's also a hash of the actual, a shot one hash of the actual commit contents. And the commit objects themselves refer to other commits in the Git graph by referring to their commit IDs as well. So each commit object actually encodes its parent, or parents, in the case of a merge commit. Now, all of these commits, if you sort of trace their relationships, build up a graph. And it's directed because each new commit refers to previous commits in its history. And it's acyclic, because each commit can only refer to commits that already exist inside that graph. So you can never create a cycle. And this is known as the Git DAG, which is the data structure that underlies Git. Now, to understand why Git has such a hard time tracking binary content, we actually need to look at the structure of these commit objects. So Git also has a cat command called catfile. If you pass it the dash p flag for pretty, you can use it to inspect any object inside this DAG.  And actually pretty lightweight. As I mentioned, they've got a reference to its immediate parent. They have a thing called a tree, which we'll come back to in a second, and some committer and author metadata. These will usually be the same person, unless you're working with patch sets or something like the Linux kernel, where someone different might be actually authoring the code and committing the code. And then you have a commit message as well. So the tree here is another type of object that sits inside the DAG.  So all of the contents of your repo at that point in time are referenced by this tree. And if you use that catfile command again, you can actually inspect the contents of this tree. And it looks a lot like a directory on a file system because that's what it represents. You've got file modes. You've got the type of each object sitting inside that tree, which is blobs and trees. So trees are nested subdirectories. So each of these trees represents the top level directories inside your repo. And each blob represents a file sitting in the top level of your repo. So we can trace these relationships down using catfile if you like, or just by checking it out into a directory, and finally get the contents of your repository for a particular commit. Now, the reason why Git doesn't handle large binaries very well is that Git actually creates a new one of these trees every time you create a commit. And every time you change a file, it has to create a new one of these blobs to represent that file's contents at that particular point in time. Now, because Git is content addressable, each one of these is addressed by one of those char one hashes of the object's contents. It's very good at reusing existing objects if they don't change. But every time you change a file, you have to create a new one of these blobs and trees all the way back up to the root of that particular commit. Now, imagine a trivial case where we have a repository containing just one large file. Say, a high resolution photo of an elephant. If I go in, open GIMP, and then change the hue of that elephant to pink and commit it to my repository, then it's going to create a new blob of exactly the same size, doubling my repository to 100 megabytes. And every time I modify that file, it's going to increase the size of my repository again by whatever the size of that file is. Now, Git does actually assemble all of these blobs up into a thing called a pack file, eventually. And it does do some delta encoding at that point to sort of compress it, mainly so it can send it over the wire efficiently. However, delta encoding doesn't tend to work very well for a lot of binary file types, because they're already compressed.  And because Git is a distributed version control system, this is where you run into real problems. Just like any version control system, you eventually have to push those versions to the server. But unlike centralized version control systems, everyone else on your team has to pull down every version of that file that's ever existed. Even if they're only really interested in the latest version of those changes, they still have to pull down that full history. So that means the load on your server grows and grows, your fetches and pushes get slower and slower. And basically, your team comes to a grinding halt, because they're just taking so long to work with these Git repos. So Git LFS, as I mentioned, is a joint project between Alasian and GitHub that solves this problem really nicely. It's not the first attempt to solve large problems with Git, but it is the best one so far in terms of seamlessly integrating with your Git workflow. Git LFS piggybacks off the existing Git commands you're already using, so you don't really need to learn many Git LFS commands at all to start using it with your existing repositories. So the way that Git LFS works in a nutshell is instead of storing these large blobs directly in your DAG as part of your Git repository, instead, they get replaced with lightweight pointer files that don't have a direct DAG reference to those large objects. And the content is actually stored in a separate segregated Git LFS store. It's not actually part of your repository anymore. Now when you do a push, these large objects get transferred to the parallel LFS store, and your DAG gets transferred to your Git host as normal. But when you do a Git pull, your DAG gets fetched, and you only have these little lightweight pointer files, which are like 100 bytes each, that get fetched instead of the large content. And then LFS lazily downloads only the large content needed during the checkout process. So it's sort of broken the distributed part of Git in that you don't pull down the full repository history. And then if you go back and check out a previous commit, Git LFS will lazily download the content again as part of that checkout. So you only grab that stuff just in time as you need it rather than eagerly all at once. Now if we use that Git cat file command again, we can see the actual contents of one of these pointers. And they really are lightweight. It's three fields. There's a version URI, which is basically a fancy new way of doing a version number. An object ID, which is a SHA256 hash of that object's contents. So one interesting thing to note here is that it is content addressable, just like Git, but it uses SHA256 instead of SHA1. The principal reason for this is that SHA1, what Git is 11 years old at this point, SHA1 was thought to be a little more secure than it is, where it's been found out to be. So SHA256 is kind of a more modern equivalent. Also, some storage providers have built-in support for SHA256 validation of objects. So if you're using something like S3 as a back end for LFS, then you can leverage that SHA256 validation automatically, which is kind of a nice byproduct of using that too. Then you have the size of that object in bytes. So one of the really nice things about LFS is that it's cross-platform. It's built-in go and available via homebrew, or I probably should have had DNF or apt or something up there. Those packages are available for those as well. Once you've got the binary on your path, you simply need to run Git LFS install to initialize it for your entire system. And what this really does under the hood is make a modification to your global Git config. It adds this thing called an LFS filter, which you can use later to bind certain files to the Git LFS clean and smudge filters, which are responsible for transforming those large files into pointers and back again. Oh, yes, man. Yes. Sorry, so I'm just recording this as well. So the question was, use the term lazy before. So it's lazy in respect that it doesn't eagerly download all of your large history during the pull process, but it will download it during the checkout process by default. Exactly, yeah. There are some ways to actually force it to eagerly fetch history as well if you know that you're going to need it in the future. And I'll get to that in a later slide if you like. Exactly, yeah. So the idea is that you only pull down the large content that you want. But if you know in advance that there's going to be some commits that you do want that large content for, you can actually tell LFS to pull that down. So a pretty common pattern is to do an LFS fetch and go to lunch or something and then come back and work with that large content. So get to a clean and smudge filters in just a second. But once you've got this initialized globally, you can start using the Git LFS track command to tell LFS which types of files you want to track using LFS in a particular repository. So this is really the only command you need to know as a regular Git LFS user. Because almost all of the other interaction with your Git repos will push and pull and check out those LFS files for you automatically. What this does under the hood is add an entry to your Git attributes file, which binds a particular pattern to that LFS filter that we just set up. Now these patterns are exactly the same as the Git ignore patterns that you're probably used to using already. So you can bind different directories or specific file names or any pattern that you like. So now let's take a look at how that Git LFS smudge filter works. So the way that LFS files get stored in your local LFS cache before it gets transferred to the server is by intercepting the Git add command. Because this is when LFS typically adds new objects to that Git DAG. So just to add a large file that I'd made some modifications to and when I run Git add, instead of just copying those contents into my repository history, instead it gets handed off to this thing called the LFS clean filter. So it's responsible for cleaning objects before committing them to the graph. So it takes a SHA-256 hash of the object's contents and then stores that object inside the Git LFS object cache, which is like this parallel storage alongside your Git repo. And then it creates one of those pointer files that we looked at using that hash and then adds that to your Git DAG instead. So instead of adding 50 megabytes to the DAG, we're only adding a couple 100 bytes. Now when you do a checkout, the opposite thing happens. Git automatically hands off this pointer file to the Git smudge command. Again, using that filter binding we saw before. And then the Git smudge filter goes off and looks in your local LFS object cache to see if it could find a blob that matches this particular SHA. If it can't, then it goes off and reads through to that backing LFS store. So this is when the download will happen during the checkout process. Once it's found the object, it writes it out in your work tree. So one of the nice things about Git LFS is although I've just told you about this pointer file format, you probably don't need to know that because in actual usage of Git LFS, you won't see them because they get transformed into pointers automatically during Git Ad and then transform back into large files during Git Checkout.  So that's how ads and checkouts work. Now I want to talk a little bit about how files get sent to and from the server using Git push and Git pull. So after you've made some modifications, Git LFS uses a thing called a pre-push hook to intercept the Git push command. Is everyone familiar with hooks? Using a couple people? All right, a few people. Yeah, so Git hooks is basically Git's extension system for intercepting certain commands. You can intercept basically everything that Git can do.  So it extracts it out of the branch name and then puts it in my commit message automatically. Other people use things like post update hooks on the server to notify chat systems when a particular branch is updated or pre-commit hooks to make sure that all of the to quickly run the unit tests and then make sure tests are passing before a commit actually takes place. Now pre-push, as it's probably pretty obvious from the name, intercepts the push command and takes some action before the push occurs. So if you've made some modifications to Git LFS files and then you run a push, then you'll see some output from LFS saying it's transferring these files to the server before the rest of the DAG gets pushed to your repository host as normal. Similarly, when you do a pull, you'll see some output and this is coming from that smudge filter saying that it's downloading files that it needs to replace those pointer files in your checkout. Now one of the things you'll notice that you don't see as part of this is any sort of authentication prompt. And this is one of the places where Git LFS really works nicely compared to some of its competition. So Git LFS leverages your existing authentication with your provider. And not by just blindly sending your credentials to the host, but the Git LFS aware server actually tells the client how to authenticate with whatever your storage mechanism is. So the way this works is in the simple case with like an HTTP repo. The Git LFS client appends a special path to the end of your remote URL, which is slash info LFS objects batch. And a Git LFS aware host like Bitbucket will know how to respond to these requests. Basically it posts up a big JSON structure saying, hey, these are the objects that I need in order to fulfill this checkout operation that I've got locally. Then the server responds with some hypermedia telling the client where to download those objects. But what's really nice is the server also tells the client how to authenticate that request by passing down a set of headers. Now in the case of Bitbucket, because we control both the LFS store and the Git store, we just send down a simple JWT signed token saying, hey, this is the username who's making this request. And then the server can just validate that JWT and go, okay, well, that's the user that's authenticated. But the fact that we're using this hypermedia based system gives you a lot of flexibility as a Git LFS server implementer. Because we could pass down some basic authorization header to use with S3, for example, or OAuth, or really any authorization scheme or header scheme that we can dream up in order to authenticate that request. So it's quite a flexible way in order to broker the conversation between your LFS store and your LFS server. So that's how LFS works. Now I wanna talk a little bit about how you can convert your existing repositories over to use Git LFS. Now I mentioned that Git LFS track command. Now unfortunately, if you've already got large files in your repository, running LFS track won't actually reduce your repository size because it's just replacing the versions of those files in the next commit with pointers. So you still have all of these different large files littering your repository history. So you need to do something to get rid of those. Has anyone heard of Git filter branch before? Couple of people? Okay, yeah, cool. So filter branch is kind of the Swiss army knife of repository history rewriting. You could potentially go back and delete all of those large files, but that would be unfortunate because then you wouldn't actually be able to retrieve those anymore. So instead of deleting them, you can actually go back and rewrite your repository history to run the LFS track command using filter branch. Now this is kind of insane. But you know, kind of genius. This is actually from Andy Neff, one of the core Git LFS contributors. These days I don't recommend doing this, mainly because of the complexity, but also because this takes a huge amount of time to do. It actually has to go back and run this command on every single commit, which is massively time consuming. So instead, there's this tool called the BFG repo cleaner. And I recently discovered that the BFG isn't actually named after the gun in doom or Roald Dahl's big friendly giant. It's actually Git filter branch, acronymed and backwards, because really it's a superior version of Git filter branch built for rewriting your repo history. And the reason it's faster than filter branch is it's been specialized to only do a couple of things. It's actually built by a gentleman named Roberto Tiley from The Guardian.  So if you had a file that shouldn't be in your repo history and you wanted to delete it, you could use the BFG to go back and expunge it from every single commit. You could also use it to blow away complete directories or even replace individual tokens within files. So if you've ever found a dev on your team who's committed a password or an AWS credential or something like that, you can use the BFG to go back and replace that with asterisks or something throughout your repo history, which is pretty handy. It's also significantly faster than the Git filter branch.  BFG is written on top of JGit, which is a Java re-implementation of Git, which is pretty performant these days. And also it memoizes each blob and tree that it's already processed. So it doesn't go back and rerun the same command on the same object. So it's kind of taking advantage of Git's content addressable nature. I get that 10 to 720 figure from a spreadsheet that's attached to the Git LFS repository on GitHub. They've run Git filter branch and the BFG side-by-side on a bunch of different projects and then measured the speed difference and then published that to kind of show off. And the most important thing is as a version 1.12.5, the BFG has built-in support for Git LFS. So instead of this very impressive filter branch command, you can run convert to Git LFS with the BFG, which as I mentioned is built in Java, so very cross-platform. So you just pass it the pattern that you want to convert to LFS, and then you have to pass the no blob protection flag, which I admit is a little bit non-intuitive. But what that means is it'll also rewrite the current commit that you have checked out. By default, the BFG doesn't do that because it assumes your repository is in a known good state by the time you run it. However, for LFS conversion, you probably want to rewrite your tip commit as well. Little product plug here. If you are using BitBucket already and you want to enable Git LFS, you just need to check the handy allow LFS button or checkbox in the repository settings. We actually just launched support in BitBucket Cloud as well about a month ago. It's still in beta, but if you want to test it out, hit the start using Git LFS button in your repository, and then all of the rest of your repository UI will start reading through that Git LFS store automatically, so you'll see it in diffs and pull requests, just as if it was tracked in your normal Git repository. So that's how you migrate over to use Git LFS. Now I want to give you some tips for using LFS in a team context. So the first thing that you need to know about working with binaries in Git, whether you're working with LFS or not, is you have to be very, very careful about merge conflicts. Now Git is very, very good at resolving changes to the same text file on different branches, but if you make any modification to a binary, then it is going to conflict because Git has no idea of how to semantically apply changes from different developers to the same binary path. So yeah, and this is really unfortunate because binaries in particular often take a long time to modify. It's not just a case of copying around some text, you have to open whatever specialized tool you're using and then apply your changes on top of the other person's changes, which is really frustrating. Now traditional centralized version control systems like Subversion and Perforce have an answer for this already, locking. Now this is a bit of a dirty word in distributed version control because everyone's used to having these nice little segregated branches or forks where they can do whatever they want and then reconcile those changes with their upstream repositories later on. However, Git LFS is going to implement locking and it's sort of in the process of being done but it's not yet available in any releases. But the way they've implemented locking is really neat. And to explain how it's being implemented, I want to first talk about how you definitely should not implement locking in a distributed version control system. Now if you're going to do a naive implementation you might think, okay, to lock a file, I really want to serialize changes to that file to a single developer. So probably the easiest thing to do is to serialize those changes on a particular branch. So you could theoretically say, okay, a developer can acquire a lock on this path on branch X and then make some changes and then release that lock once they're ready for other developers to go in and make their changes. Now this would work. You'd no longer end up with conflict because you're forcing everyone, like forcing a single developer to just work on that one branch. But this is pretty lame because Git is awesome because of its branching. It's nice that everyone has these little isolated environments in order to work on their features. And if I'm on my feature one branch, I may not want to merge master into my branch in order to be able to acquire a lock. So the proposal that actually came from Steve Streeting, one of the Atlassian Derbs attached to Git LFS is for a multi-branch model for locking. And kind of the way that this works is that anyone can acquire a lock on any file provided that they have the latest version of that file on their branch, which is a little bit different to just serializing changes on a single branch. So for example, say a developer wanted to make a change again on master. They could acquire a lock, make some changes, and then release that lock. Now imagine another developer wants to make a change on the feature one branch. Now if they're okay with merging master in or rebasing their branch on top of master, then they can, if they attempt to acquire a lock that's gonna fail because they don't have that latest version on their branch yet. But if they rebase, then they will have that latest version and now they're okay with acquiring a lock and making some more changes. But just say they didn't want to rebase or bring the history of master into their branch via a merge. What they can do is actually cherry pick that commit on top of their branch. So there's no direct commit history relating to that and then make that modification. And in fact, they don't even have to cherry pick the commit. They could actually just do a checkout of that particular file on top of their branch as long as they have an object which matches the SHA-256 hash of the latest available version of that path, then they're allowed to acquire a lock and modify it. So this is a much more flexible way of doing locking in the DVCS world. And really what's happening here is we've built kind of an orthogonal structure for a particular file on top of Git's branching model. So we no longer care about branches in terms of serializing changes to this file. We just have to make sure that we have this kind of continuous thread of modifications based on the last time it was updated rather than the actual location where it was updated, which is a much, much nicer way to do locking in a DVCS. At least we think so. So as I mentioned, the command, there is a little bit of work that has shipped or is on master currently, but the commands themselves aren't available in any Git LFS release yet. They're kind of looking like they'll shape up like this, basically a simple lock command where you lock a particular file and then that publishes the lock to the server. A Git LFS unlock command, which can be used by the developer who created the lock or can be forced by another developer. So really these locks are advisory rather than kind of like a hard and fast rule. So if you do really want to make changes to this binary and then you're happy to resolve the conflicts later, you can force unlock something locally. And then there'll be a simple command to list locks as well. Now, unfortunately, this is all kind of in flux. You can't use it yet. Until then, the best thing to do is to tell other members of your team that you're actually working on a large file before you start making those changes. So if you've got two artists on your team and you're thinking about going and changing that model object or that texture, just let them know that that's what you're doing. You're kind of manually past the mutex rather than running into conflicts later on. So I've mainly been talking about how individual developers interact with a particular Git LFS repository. Now I want to talk a little bit about how you can retrieve content that the other members of your team are working on. So there's a command called Git LFS fetch, which I think I briefly mentioned before. What this typically does is retrieve content for your currently checked out commit. Now you don't usually have to run this command yourself because that happens as part of the checkout process. However, you can use the dash dash recent option to pull down content from other recently updated branches. Now by default, this is any branch that has a commit on it that's newer than seven days old. And if you like this behavior, you can make it permanent using the fetch recent always flag. Git LFS is highly configurable. There's all sorts of options we'll be talking about in a second. And you can also configure some other recency behavior by modifying these properties. So you can change that threshold of what Git LFS considers recent by setting fetch recent rest days. You can also retrieve content relating to commits that aren't the tip of a branch by setting fetch recent commits days. So what this does is it finds any commit, or sorry, any branch that's been modified within that recency threshold, and then it walks back that number of days and pulls down any LFS content relating to those branches. Now, because these are days rather than just a raw commit count, this can potentially be a huge number of commits, which is why it's set to zero. So it really depends on your repository structure and how fast your branches move as to whether you wanna turn that setting on. However, if you're thinking about doing some cherry picking or some rebasing of your teammates' branches, just not really something you should do, then potentially you can set that value to pull down their history, or if you wanted to review interstitial versions of files and that might be useful as well. You can also turn the LFS fetch recent remote refs option off, if you like, so it defaults to true. What that means is it's gonna pull down LFS content for every remote branch, as well as branches that you've actually checked out locally. Again, depending on your repository and the size of your team, this might be a huge number of branches. So if you're working on a very large repo and want to use the recent flag, you might consider turning that off. Once you've retrieved all of this content, you might want to go and clean up that content at some point because it's gonna be just sitting in that local LFS cache taking up disk space. And unlike Git, Git LFS does not automatically prune files at any point because it's being a little bit conservative about going off and deleting your data.  Specifically, it adds an offset to that recency threshold we were just looking at and then deletes any content older than that with a couple of caveats. So it will never delete content that's currently checked out because it assumes that, quite rightly, assumes that you're still gonna need that. And it will also never delete content that relates to a commit that you haven't yet pushed to the server. So it compares the values of your local branches and the remote branches and then doesn't delete any LFS content that's referenced by those commits. Now there is one setting which I really recommend turning on, which is prune Verifier Remote Always. Now what this does is actually check with the server that the LFS content that it's deleting actually still exists on the server. The reason this is defaults to false is because this really, really slows down the prune operation. It means that it has to, well, make some requests to the server, but it also means it has to go off and check every single object in LFS to see whether it's referenced. Sorry, not whether it's referenced. It actually goes off and checks with the server every LFS object rather than walking your dag and seeing what's referenced in deleting everything else. You can also set the prune Offset Days value if you want to change that threshold offset to something a little more conservative. So for instance, I have it set to like 21 or something because disk space is relatively cheap and I kind of like to keep these objects around for a little longer. Now, so this is how you clean up your local LFS cache. One of the interesting quirks or maybe it's just sort of one of those things that hasn't been built yet is the Git LFS API doesn't specify how to delete objects on the server side. So there's no way you can do a remote prune of your Git LFS store. So instead, each LFS implementer has been kind of left up to throwing devices as to how they build that. As far as I know, Bitbucket is the only implementer that actually lets you browse your LFS objects on the server and delete them. I think the others maybe just clean up files when you actually delete the repository. So this is kind of interesting. You have to be a little bit careful and we've got some commands there to show you how to, like if you find local references, it'll tell you how to find out which commits are referencing this particular object. But if you do delete a file that's still referenced by a particular commit, Git LFS will still work, but it will just check out that pointer file into your work and copy rather than checking out that large file. So if you're scrounging for disk space on your server, you might end up deleting files that still potentially referenced in your Git history and they just won't be checked out automatically for you anymore. So that's how that recency stuff is how you can check out more large file, more LFS history than potentially you need. You can also configure Git LFS to check out less LFS content. Why would you want to do this? Well, in some situations, you may not need all of the LFS content at for a particular commit.  So you might configure your CI script to do an LFS fetch with the exclude flag to prevent all of those assets from being downloaded.  So for example, an audio engineer or a graphic designer might only pull down the assets they're likely to be working with to save on transfer costs. And again, you can make these permanent using the fetch exclude and fetch include properties. And just like all of the other settings, these can be defined either for a particular repository or globally for every repo you have locally, which is pretty handy. So speaking of audio engineers and designers and potentially other developers not interested in using Git from the command line, Source Tree does have built-in support for LFS. Interestingly, kind of the principle at Lassian Committer for the Git LFS project is Steve Streeting, the guy who built Source Tree initially. So it has really, really good support for LFS. It has some cool stuff like it'll fix up any broken Git repository, or any broken Git LFS installations you have locally. So if that pre-push hook is missing, it'll install it for you. And it also mostly it's seamless. So if you do like a pull that'll pull down your Git LFS content too, just like regular Git, but you can explicitly invoke LFS commands through the options. It is a bit cheeky because we don't actually have a Source Tree variant on Linux just yet, but it does work on OSX and Windows. So if you're collaborating with people on those platforms, it can be useful. So I think that's all I've got for today. If you're interested in learning a bit more about the project, go check out the docs on gitlfs.github.com, or you can see the source code as well. The source is really interesting. It's built in Go, as I mentioned, but it's also a really good example of how to extend Git. So if you're interested in building your own Git hooks and extensions, or your own smudge filters and clean filters, having a look at how LFS is implemented is a good way to get inspiration for that. And as I mentioned, it's available in both bitbucket.org and Bitbucket Server as a version 4.3. And on Bitbucket.org, it's both free and paid accounts. Everyone can use LFS. For example, I use LFS for tracking my slide presentations because it's a nice way to back up versions in case I screw something up. Thank you very much for your time. So I think I've got plenty of time for questions. Yes, man? Yes. Yeah, so Gitanax was definitely a good project as well. Gitanax has more support for specifying different remote stores. So you can use your local file system as a Git LFS store, or you can set up SSH remotes, or various other things. The problem with Gitanax is you sort of have to do all that configuration yourself as a developer. Because Git LFS delegates authentication to the server, you don't have to know any special Git LFS commands. You can just use your regular push, pull, commit, checkout, and it will do everything under the hood for you. So I think the big advantage of LFS over Anax is that it's turnkey. Like it works out of the box, and you don't have to train up the rest of your team on how to use it. Yes, man? Interestingly, yeah, so there are a couple of things going on in the main Git project. I know Christian Kader was actually working on external object database stores for core Git. So potentially one of the ways that could work is you could store your LFS objects in an external database, rather than having to use LFS at all. But I think that's still a work in progress. The Git contributor summit earlier this year, certainly large object storage was kind of like the number one topic debated by the Git contributors during the summit. So it's definitely, I think, high on the mind of Jeff King, and Junio, and the rest of the core maintainers. But I don't think we'll be seeing it in the next few releases. Any other questions? I guess? Oh, OK. Nice one. Any other questions? Yes, man? Is it faster than a single depth check out? Do they need to deepen that check out at some point? Like if they want to commit? Gotcha, gotcha. So I know that single depth checkouts, there are some limitations there, but usually it's when you need to write back to it. So I think as a relatively recent version of Git, you can commit back and push from single depth, or shallow clones. But there are some problems with doing mergers, because Git's recursive merging algorithm needs to kind of walk back and find common ancestors and things like that. I think in your particular case, if you really were just doing a single depth check out, it would probably be, yeah, marginally fast thing at LFS. There will be some advantages that LFS will bring soon. So in 1.3, we landed a way to extend the way that files are transferred from the server. So with Bitbucket, we're building this kind of chunked encoding thing where you only need to fetch local chunks of files that you don't already have. So potentially if you're cloning and then fetching later on or doing multiple clones from the same repository, then you will have better performance with Git LFS. But yeah, if that's not likely to happen, then a single depth check out will probably work for your purposes. However, if you're using like a CI server, or if you're personally ever going to be working on it from multiple places, then you might benefit from using Git LFS just from your own usage to restrict your having to pull down that full history. Yeah, yeah, fair enough. Cool. Oh, yes, mate. Yes, what is the backup or data migration to a different server story than like? Yeah, absolutely. So we are essentially breaking the distributed part of Git with Git LFS. In terms of backup, you could either just back up your entire system, as you're probably already doing, or your particular home directory for something like Bitbucket server. Or you can set up a specific Git LFS clone, sorry, backup. That Git LFS fetch command has a dash dash all property as well. And if you pass that, it'll go off and fetch all of your LFS content from the server. So if you really want to kind of keep the D&D VCS, you could actually override your LFS fetch settings to always fetch all of that content. But yeah, that would sort of circumvent the reason why you're using LFS in the first place. Absolutely. There are ways you can do full backups of LFS if you need to. Yes, mate? CI systems that support LFS. So Bitbucket Pipelines does now, I think. Other than that, I mean, even if the CI system doesn't have specific support for LFS, you could always have Git LFS fetch as your first command and make sure that you have the LFS binary installed. And in fact, probably a lot of CI systems, unless they're based on something like JGit or LibGit 2, will probably just work out of the box if they have LFS on the path and have Git LFS installed on, because the global config will pull down those files automatically. Cool. All right, thanks very much for your time.


Thank you very much. It's an honor to be here this afternoon. I'm going to speak from the podium I find that I tend to be more energetic if I if I'm standing than if I'm sitting What I'm going to do is talk about Trump administration international Economic policy, and I think the value added that I hope to deliver is some discussion of the specifics of process protection That's underway, and then I will make an argument about why the next couple of years may be particularly Dangerous due to the interaction of Trump administration macro and trade policy But first I want to make a really simple point which it is an explicitly Protectionist policy last night. I went back and reread his inaugural address, and it contains the following passage We must protect our borders from the ravages of other countries making our products stealing our companies and destroying our jobs Protection will lead to great prosperity and strength now That statement is a continuation of campaign themes There was a focus on trade deficits including bilateral deficits And then there were two other themes that provide from a Trump standpoint both an explanation for the trade deficit and a location for the Solutions one was the issue of currency manipulation. The other was so-called disastrous trade agreements There has been continuity post inauguration He has undertaken some executive actions that have tightened up government procurement made it harder to get visas to come to the United States And there has been an aggressive use of contingent or process protection, which I'll go into detail about in a moment Finally as we've heard from other speakers There has been the withdrawal from the TPP and the renegotiations under threat of abrogation of Chorus and NAFTA Okay, what about that new protection the United States like other countries have laws on anti-dumping and countervailing duties But the Trump administration has been distinguished by two characteristics One is the use of rather obscure parts of US trade law including the global safeguards Which doesn't even require injury to domestic industry and the use of section 232 national security protection Moreover the second characteristic is the Trump administration has been unusually prone to self-initiate cases and that matters because historically if the government self initiates the case rather than waiting for a Domestic firm to complain there is the higher likelihood of protection actually being implied So if you simply take the cases from the first hundred days of the Trump administration and assume and this is an assumption That protection is actually applied as you can see in the upper panel the share of US imports under protection doubles And you see in the lower panel it breaks down that by country South Korea would be the worst affected The problem for a country like South Korea is while some of these policies are aimed at China South Korea produces products such as solar panels and steel and washing machines that get caught up South Korea is essentially collateral damage The single biggest change in protection would be Canada because of the perennial software lumber case And as somebody mentioned yesterday the real problem with this is that given the United States prominence in the system the likelihood that there will be emulation by other countries The Trump administration as we've heard is also scrapping trade agreements. We are renegotiating NAFTA Dick Cooper pointed out yesterday that some of that is a constructive agenda updating But what dick didn't mention were the bad ideas that we heard some about this morning a five-year sunset provision Which basically undercuts the idea of having a trade agreement because it means that companies cannot invest with any certainty About the rules of the gamer be Titan rules of origin particularly in automobiles The rules of origin that the United States is proposing on automobiles are designed to disrupt the existing supply chains The North American auto market is highly integrated if these rules go through it will mean real Inefficiency is introduced into that North American market The long-term effect will be the movement of production from North America into China And as we heard earlier this morning these sort of strange arguments about trade balances if the If the renegotiation fails and NAFTA is abrogated the snapback for Canada is to the US Canada FDA And you can imagine the US and Canada basically working out a new deal that modernizes that agreement But for Mexico this the threat is much more existential there would be real impact in terms of production in Mexico and Strangely from a Trump standpoint the likelihood would be a depreciation of the peso and an increase in the bilateral trade imbalance not a reduction The Korea free trade agreement was slated for abrogation Fortunately Kim Jong-un stepped in and with the sixth nuclear test took that off the agenda but it's been simply pushed to the back burner and There is still the possibility of abrogating chorus now in Anticipation of the election last year I Did some modeling along with some colleagues at the Peterson Institute to look at what the impact would be in the United States modeling trade wars with China and Mexico and as and what you can see from That map is that the the effects are Significant and they are they are not uniform across the states Capital goods industries would be the worst hit both because of decline in domestic investments associated with the trade war as well as a reduction of exports of those goods But what's really interesting is there are large employment losses and non-tradables and because of the pattern of hiring in those sectors What we find is that the the most of the US casualties in a trade war would be among the most vulnerable people in Society that the effects of a trade war in the United States would be regressive Washington poor Washington is the worst affected state But we also looked at some scenarios that looked at asymmetrical forms of retaliation Things like China stopping buying aircraft or having an embargo on soy beans or instructing state-owned enterprises Not to buy us business services We've also looked at what might happen in some cases if chorus were abrogated That would include the loss of preferences in the beef market to countries like Australia, Canada, New Zealand Which we expect would mean the elimination of us beef Exports and at least in the short run as well as also loss of business services to EU competitors The case of aircraft aircraft production is highly localized certain geographical areas are hit hard in the case of business Services the areas that are hit under either of these actions Basically constitute a map of the high-tech urban areas of the United States But from a political economy standpoint possibly the most interesting part is The two agricultural cases you can see on the map There is a patch of green that runs from Mississippi through Arkansas, Tennessee and into Missouri That's the impact of a soybean embargo by China the loss the reason it's very interesting is twofold First of all if say you're in Seattle and you lose your job You're losing your job, which is not good But you're losing it in the context of a large urban labor market with public transportation If you lose your job in one of those contiguous rural counties You are in real trouble and the job losses in direct plus indirect in some of these counties one county was as high as 25% There were about a dozen counties would where it exceeded 10% Likewise in the beef case you can see those yellow dots. They are in these sort of plain states the reason why this is interesting is that those areas are represented by Republicans and If the if the Trump administration is to be constrained politically it is likely to become through Agricultural interests in the United States The real threat though is the interaction of the macro policy and the trade policy We the United States for a variety of reasons is likely to adopt Expansionary fiscal policy that's going to lead to a growth spurt widening budget and trade deficits appreciating exchange rate and then you face the prospect of the Trump administration reaching for Protection trying to square the circle with that increasing trade deficit and what we could get is a very nasty version of the first Reagan Administration that an administration that in the infamous words of then Secretary of Treasury James Baker Imposed more protection than any US presidential administration since Herbert Hoover This is a period of time well known for voluntary export restraints the Current US TR. Mr. Ambassador Lighthizer was actually one of the negotiators And is well versed with this kind of action There is one huge difference though in the context of the Cold War and normally I have to say most of you Don't remember that but in the context of Cold War actually this audience you do remember it You are all senior officials at the time In the context of the Cold War we were the ultimate United States was the ultimate a political and guarantor of Japan and However grudgingly at the end of the day the Japanese were going to go along with American demands in the trade policy area Needless to say the relationship between the United States and China today Could not be more different. So just to recapitulate Well, I just lost it This is a new policy. There is a real there. This is a break with the past It is explicitly protectionist it is in the works So some of these decisions for legal reasons have not yet been made But they are in train and the conflict between trade and macro policies are going to make it worse To the detriment of the United States and all of its trade partners. Thank you


here again what we're doing is we're saying I'm taking this 400 times 1.03, 103% 1.03 that gives us the 412 times the 700 unit price so so we don't really need to calculate May but if we wanted to we can say okay May is 400 units times 700 per unit enter that comes out to 280 sales and then June is going to go up to 214 412 units times 700 per unit and that gives us the 288 for now what we're looking for this is the sales and what we're looking for is the the selling expenses so they they're telling us that the selling expenses is 3% of sales we have commission commission rate is going to be 3% so once again that's point or 2% sorry it's 2% 0.02 so I'm going to go back on there on that 0.02 I'm going to go to the home tab we're going to go to the numbers group and again I could increase the decimals 0.02 is the same as if I say the percent sign 2% and that means that the commission will be the sales of 288 4 times 2% times 0.02 in the calculator and that'll give us the commission of this 5768 we also pay a salary so we have a salary a sales salary to the sales manager of 3000 therefore the total sales then would be the selling expense would be the commission 5768 plus the salary that we pay them and that will give us the 8768 for the selling expenses so note that the problem the main issue with this type of problem is to basically format the the information put it down in a format that works obviously an excel it's nice because you can move things around if you don't have excel then you need to get used to how to format different types of problems so you can do it efficiently by hand it would be the same type of thing graph like this but you want to be able to efficiently do that by hand all right next one here once again I'm going to try to start off by reading that last line first to see if we can get some information on what needs to be done before we read through the entire thing so the last line begins right here with budgeted purchases of product a for the year would be so we need to find out what what the budgeted purchases of a will be so keep that in mind as we read through the entire thing here starting from the top we have the sales budget for corp shows 20,200 units of product a and 20,200 units of product b are going to be sold for prices of $10 and 20 cents and $12 and 20 cents respectively the desired ending inventory of product a is 30 percent higher than its beginning inventory of 2200 units the beginning inventory product b is 2700 units the desired inventory inventory is 3200 okay so we're going to try to focus in on product a so we need to figure out what we need to purchase now when we think about what we need to purchase we have to start off that that conversation out with how much do we think we're going to sell how much do we think we're going to sell with product a throughout the year so projected sales of product a because that's what we're focusing on here is 20,200 units 20,200 so that's how much we need 20,200 units now that if that was it if we were starting from nowhere that's how much that's how much we would have to basically purchase or produce if we wanted to sell that much but this is not our first year for one which means that we have beginning inventory already so we don't have to have the whole 20,200 because we already have some in beginning inventory and it's also true that we want to basically a cushion at the end so we want a desired ending inventory and so so we want something at the end and what will that desired ending inventory be now they're gonna they're gonna give us the beginning number work that's what we'll typically know and then we're gonna basically calculate off that what the desired ending is so they tell us that here the desired ending inventory of product a is 30 percent higher than its beginning inventory so I'm going to do that in a separate calculation we're going to say the beginning inventory is 2200 2200 and we want it to be 30 higher because it's going to be a 30 percent higher for the ending inventory so that would be 0.3 30 percent or if we go to the home tab I'm going to add some decimals it's 0.3 that would be 30 percent or if we hit the percent sign 30 percent same thing that means that we want an increase of 2200 times 30 percent and that will give us the increase of 660 that's the amount of the increase so what's the ending balance going to be then we want it to be this 2200 plus the increase the 30 percent increase of 660 now once again we could do that quicker we could do that quicker we could say okay the beginning inventory is 2200 2200 times not 30 percent but 100 plus 30 1.3 1.3 and if we go to the home tab numbers and we add decimals it's 1.30 1.3 is the same as if we make it a percent the 130 percent and we do that with one calculation then we're gonna just say okay I want this 2200 times the original 100 plus the 30 130 and that will bring us to the 2008 60 so if we were starting at a point of zero we don't have any any we don't have any inventory we would need to produce the projected sales in units 2200 and we would have to produce enough to have our desired ending inventory which in this case happens to be the beginning inventory I'm just going to recalculate it here 2200 times 1.3 130 percent enter so there's there's that okay and then that's what we would have if we didn't have something in there already but we already have a beginning balance we already have a beginning balance and we're going to subtract that out so if we didn't have any beginning balance we would have to have the 2200 plus this much for a cushion at the end but there's already something in there in the beginning so we're going to say minus the 2200 that's in there at the beginning so if we sum that up then we're going to say what we need to produce then is going to be this 2200 plus what we want at the end minus what's already in there and that will be the 2008 60 if we did that in a calculator all we're doing there would be of course taking the 2200 plus the 2860 minus 2200 giving us the 20860


We will continue our discussion on restricting basic Turing machine models in some natural fashions and in fact, we will find all such restrictions do not really cut down the power of recognition. So, today we shall we will consider counter machines counter machines we can represent pictorially in this fashion that it has read only input tape and this is the finite control. So, this finite control the machine itself can be in a number of finitely many states. Now, what it has besides of course, these two a number of counters these are counters. So, this machine has k counters these are counters and a counter is a counter can store any non negative integer. Therefore, it can store 0 it can store any other non negative integers and the kinds of operations allowed on a counter are this check if a counter contains 0 value that is the number which is stored in the counter. You can check whether it is 0 or not if it is not 0 of course, it is going to be something positive increment counter value by 1 decrement counter value by 1 provided this decrement you can do provided counter value stored before the decrement is positive counter value was positive. So, once more a counter is something which can store any non negative integer 0 1 2 3 we have no bound on the size of the integer it can store it what this machine can do with a counter is that it can check if a counter contains 0 value or not. So, in other words what it cannot check or what it cannot make any decision on the particular non 0 value of a counter all it can check is the value 0 or not if it is not it can be anything 1 2 whatever that might be it can always increment a counter value by 1 it can decrement a counter value by 1 that is subtract 1 from the counter value provided the counter value was positive to begin with because you see if it was 0 essentially that means we cannot decrement otherwise we would have got a negative number of course, negative numbers of things which counters cannot store. Now a counter machine therefore, will in a particular state what it will it is next tape will depend on of course, it will depend on its present state input symbols being read. So, that is the symbol under the read only input tape and because it is read only this tape head keeps moving only to the right it can never come back in the sense it of course it is not because it is just read only, but read only one way input tape and that is the kind of convention we had for input tapes for PDAs even stack machines. So, that is the standard restriction that we have read only input tape where the head moves only from left to right and so the present symbol of course, it knows at any given time it is in some particular state let us say q reading an input symbol a and now it can check whether these any one of these or all of these 0 or not. So, essentially the information for C 1 to C k it can check is 0 or non 0 for example, if they are all 0 maybe the next take will be something let us say p and then it should say what are the operations done on C 1 to C k. The operation would be one of these basically either increment by one or decrement by one. So, once more a move of counter machine we can describe by something like this. So, just for the sake of example, let us say we have three counters. So, that move we can say the present state the input symbol being read and let us say we can say here positive 0 positive. What we mean is suppose we had three counters and C 1 is positive that is contains a number more than 0 C 2 is exactly 0 and C 3 is a number which is positive then depending on if this is the situation then you might say increment first of all go to next state is going to be 3 and and operations on C 1 C 2 C 3. So, you can say maybe increment C 1 right increment C 2 and decrement C 3. So, a typical move of a counter machine in this case it is a three counter machine for this example can be described in this manner that depending on the present state and the input symbol that is being read and depending on the nature of values of the three counters and that nature is whether their positive or 0 depending on this information the machine determines what it is next state going to be and what operations to perform on each one of the counters. So, it looks therefore, is a fairly restricted model compared to our basic model in the sense in our basic Turing machine model we had a tape we could have gone both ways we could have written anything so on and here whatever operations we are performing they are very restricted in nature at the same time it turns out that you know a very few counters will be necessary to capture the full power of our basic Turing machine. So, first of all one should realize that a counter can be thought of as a restricted version of a stack why because imagine a stack which has other than the bottom of stack symbol can contain only one some particular symbol as its stack symbol a counter can be seen as a restricted version of a stack and this restricted stack other than the bottom symbol bottom of the stack symbol which is a special symbol which will not occur anywhere else in the stack except here the symbol that it can contain is exactly one symbol that is for example, here only x can occur and x can occur in a number of times. So, you see such a stack you can think of it as a counter because you can check whether the corresponding counter has zero value or not that will be the case when there are no excess only the bottom of the stack marker is there. So, if you are looking at the stack and accessing the top stack element and if the top stack element happens to be this symbol then you know the corresponding stack corresponding counter contains the value zero increment counter value by one which just means push a symbol x decrement counter value one by one provided counter value as positive it of course means that if you are seeing an x as the top of the stack symbol you can pop it. Therefore, you can see that counter any counter can be modeled as a stack of a very restricted kind and once we see this we immediately know that one counter machine is a restricted push down automata. By the way we will assume that our counter machines that we are considering they are deterministic and even then ultimately what we are going to show is that with just two counters we can simulate during machine. Now, the point is a one counter is of course very restricted especially because it is also deterministic. So, it is a deterministic PDA and that to the stack can contain only symbols in this manner. So, it is a very very restricted kind of a machine. Let us now consider the case counter machines with three counter. See our strategy is first of all we show that three counter machines can simulate during machines and then we will show that just by using two counters you can also simulate during machines. And the reason for not going directly to three counter machine two counter machines is because the idea of the first proof that is sufficiency of three counters will be required you know for the proof of two counter. In fact, we will start with a three counter machine simulating a during machine and we will see how we can do with only two counters later on alright. So, what we are trying to prove now that two counters suffice this is what we are trying to prove first of all not two the case of two, but three counters suffice. Suffice in which sense suffice in the sense that with three counters a counter machine with three counters can simulate during machine right. So, our idea is going to be that you give me a during machine and I will give you a counter machine with three counters which will accept the same language as that of the during machine. The way we will do this is through the intermediate result we proved earlier that two stack machines a stack machine with two stacks can simulate during machine. So, what we will actually show will be that three count of counter machine with three counter can in general can simulate two stack stack machines and the strategy of this proof will be how do we show this that will essentially what we are going to do that will have one counter to represent one stack another counter to represent the second stack and the third counter we shall use to do the manipulation stack manipulations on these two stacks. So, strategy for demonstrating the truth of the sentence is as I said that we represent each of the two stacks a counter by one counter by basically what we mean is. So, here is we have a stack machine recall a stack machine looks like that it has some input tape and it has two stacks. So, this is stack one and this is stack two stack machine. So, you give me such a machine what we are going to do is to consider a particular counter machine which has just two counters this is C 1 and C 2 and will what we will do is C 1 to represent stack 1 and C 2 to represent stack 2 how do we make this representation. So, that you know all our operations will be conveniently done by counter machine operations the stack operations to be simulated by counter machine operations what you can think of suppose we have a stack and we had some symbols appearing in the stack and of course. So, here there are five symbols now imagine the number five four one three two one. So, what is what I am doing I am each stack symbol I am think of thinking of the stack symbol as some x i and. So, let us say there are x 1 through x k these are the stack symbols. So, there are k stack symbols in general one x 1 x 2 after all then the contents of a stack is a sequence finite sequence of with symbols from this set and now I can think of this as one this as two and this as k in a k plus one a re-representation. So, these are the digits this is digit one digit two digit k of a k plus one a re-representation of numbers and then I from top to bottom we write the k re-representation number in left to right fashion. So, this example is clear that suppose x 5 x 4 x 1 x 3 x 2 x 1 that is how the stack appeared at some point the corresponding number that I am talking of in this case the base is six because you know let us say there are these five symbols can appear we have some number and as I said that we write the number in this form well here actually I should have said that this when I write like this I would like to see it as the least significant digit and this as the most significant digit this is of course that is how we read the stack I am writing like this, but imagine the most significant digit of the corresponding number which this codes is the number which is at the bottom of the stack here and so on. So, now think of so therefore, this is a definite number and what is that number in this case when the representation is six sari. So, you can see this is going to be this is the 0th first second third fourth fifth right. So, I can think of this as 6 to the power 5 1 into 6 to the power 5 plus 2 into 6 to the power 4 plus 3 into 6 to the power 3 plus 1 into 6 to the power 2 plus 4 into 6 to the power 1 plus 5 right. So, this is a very simple idea the idea is that think of the string which is there on the stack at any time as a representation of a certain number and this number the most significant digit is appearing at the bottom and the least significant digit is appearing at the top all right. So, now this, but this is a particular number right and numbers are things which we can and this of course, as you can see this is going to be a positive number always representation of a stack contents in this manner is going to be a positive number or rather I should say non negative number. And what we can do is to say that this number is what is stored in a counter empty the stack empty means the number is 0 you can put it that way. So, now you see suppose you wanted to pop this number or rather this is a stack. So, you wanted to pop this symbol. So, then once you pop this symbol the stack would have had x 1 x 2 x 3 x 1 x 4 once you have popped the top symbol the stack will look like this. But you can easily see what is now the number that corresponds to this contents of the stack right. So, the top of the stack symbol was represented by the last or the least significant digit. So, essentially what we are doing is if you want the number corresponding to this you are supposing this original number is n all you are doing is n div k or k plus 1 we are seeing our arities in this in general it is a k plus 1 array representation. Now, in this particular case the number that I will get here since it is a 6 array representation is n div 6 right. So, this is equivalent to the number n div 6. So, obtaining the resultant stack after popping the top symbol is equivalently if you think in terms of counters is obtaining the making the integer division by a certain fixed number 6 in this case. Now, how can you carry out this in terms of a counter remember that suppose this was your stack 1 and therefore this number n was stored in counter c 1 counter c 2 would store the number corresponding to to the stack contents of the second stack and recall that we are considering 3's counter machine. So, we had a pair counter what I will do. So, this is the pair counter or auxiliary counter I will use this to find out the result and that is fairly simple is not it what we are doing supposing we had n here. So, we start decrementing n every time we decrement 6 here we add 1 to this starting of course with the value 0 is not it. So, what will happen suppose the number was let us take a simplistic case 33. So, first time you reduced this by 6 so how you why what is that 6 because that is a fixed thing that is the addity which you are using for representing numbers which is. So, therefore you know and 6 is a constant so far as one particular stack machine is concerned because that the number of different symbols in stacks will be a constant and that is the constant which is going to define your addity of number representation. So, decrement 6 times this is possible 6 or whatever that constant thing is now that since it is a constant we can do this decrement by means of a finite number of steps that is of course you want 6. So, 6 steps that will require of the counter machine 6 decrements here and once you complete all 6 without this number becoming 0 that is the numbers result you could fully take out 6 from here then you will add 1 here right. So, at that time so basically you subtracted 6 so what would you get you will get 27 having decremented 6 from here. So, once this value became 27 this value became 1 then next time another round of taking out 6 from here you will get 21 here it will be incremented by 1 so this value this counter value c 3 will be 2 and so on right. So, at some point of time you will have 3 left and this counter value will be 5 and now when you are trying to decrement 6 from here you have done 1 you have done 2 you have done 3 and then immediately we will see this particular counter has become 0. So, therefore, you know also in this process what is n mod e plus 1 in general or in our particular example what is n mod e plus mod 6. So, this would give you what is the top stack symbol which you have just popped and this will give you the value of the counter that would correspond to the stack which results after popping of the top symbol. So, what I am trying to say and this is now fairly clear that popping operation in a popping operation of a stack we get something the top stack symbol to do whatever we wish to do with it and then the stack becomes less by 1 symbol. So, both these operations we can do by in this simple manner. Now of course, you after getting the right value in C 3 here will copy back C 3 contents to C 1 because that would have been what is desired because C 1 is representing stack 1. So, any particular stack operation whether it is C 1 or C 2 so long it is a pop operation popping of the stack we can do it by this manner. It is very easy to see that pushing or adding a symbol push on a stack also can be similarly carried out. So, if you wanted to push let us say 4 on this right this was the number and you wanted to add 4 to it. That means correspondingly the number the symbol x 4 is pushed on top of the stack in the corresponding number would have been this now this has become the this 4 has become the less significant digit. How can you get the resultant number the resultant number would have been simply n into 6 plus 4 right because remember this side is the least significant digit and this side is the most significant digit. And can we carry out such an arithmetic operation using the counters only using the counter operations yes that also we can why because let us say I have a counter which is currently contains n and I would like from here finally the counter to contain let us say 6 n plus 4. Now remember we will do this using the auxiliary counter and what will be the strategy here we decrement one from here and add 6 to this auxiliary counter every time I add decrement one here I add 6. So, if I do so when this becomes 0 this has 6 n as contains auxiliary counter. So, auxiliary counter will have 6 n and now this is a definite constant that you are going to add this because of whatever reason because you know in some step x 4 was added on top of the stack. So, now you add 4 to this that means increment 4 times we will get 6 n plus 4. So, now the auxiliary counter contains the correct value to represent the new stack here the stack contains here. So, now you copy back the contents of here to here by decrementing one incrementing one decrementing one incrementing one remember it had already gone 0 and so on. Therefore, if you just perform this operation in decrement this increment this still this becomes 0 will transfer the contents of auxiliary counter to the counter of that corresponded to the stack whose operation push operation we were simulating. And therefore, my point is that both push and pop we just saw that push on a stack we can simulate by counter machines in fact just by using two counters we can simulate the push of a stack what not exactly push of any string, but what we had shown was push of a symbol one symbol, but that is general enough. Because you can always even if your p d a wanted to push a string which is whose length is more than one that is it contain more than one symbol this you can of course think of as pushing separately all these symbols in the string. So, this is general enough therefore, what I have just told you to summarize it will mean three counter machines can once represent two stacks by two counter second what is the other thing it can do that can simulate push and pop with the help of the auxiliary counter. Now what else is left in for simulating a two stack machine see a two stack machine of course reads symbols from input, but that is direct is not it because your three counter machine will also have an input tape and as it reads an input here the same input can be read the same input symbol can be read from the three counter machines corresponding input tape. The stack machine changes states with the state of the stack machine we can keep track of in the finite control of the three counter machine. So, therefore, it is not difficult to conclude from the discussion that three counter machines can tip by two counter machines by step simulate the operations of a two stack machine. So, therefore, our conclusion is since three counter machines can simulate two stack machines and since two stack machines can simulate during machines we conclude that such machines that is three stack machines three counter machines can simulate you see it is a fairly strong restriction instead of a tape of a two ring machine the memory is now simulated memory component of an algorithm is being simulated by just three counter. Now the interesting thing is that actually we can do only with two counter now let us prove this statement the way will prove this is that will show that three counter machines can be simulated by two counter machine proof idea consider a specific three counter machine. So, it is let us say it is three counters are C 1 C 2 and C 3 these are the three counter now our two counter machine what it is it going to do that it will represent all these three counters in one single counter. So, let us say C 1 dash and C 2 dash are the counters of the corresponding two counter machine and here what will do is first of all let us say that will say that C 1 dash will represent or will have all the information of all these three stacks. Now recall that these three stacks at any given time it contains three numbers N 1 N 2 and N 3. So, essentially keeping track of three counters is keeping track of a three tuple of numbers N 1 N 2 N 3 any one of which could be zero, but none is negative. So, that is a very simple way of there is a very simple way of representing a three tuple of numbers by means of one number that is well known and this is called Godel numbering. So, consider this number two to the power N 1 three to the power N 2 and five to the power N 3. Notice that these are two three and five are prime numbers and this therefore is a is one definite number N and I claim this N uniquely represents N 1 N 2 N 3. So, the number of twos in this number N the first number of factors basically two factors is N 1 number of threes as factors is N 2 number of fives as factors of N will be N 3. Now counter machines will of can perform certain operations and those operations are check if a counter is zero right these are the operation increment a counter and decrement positive counter value by one these are all by one all right. Now, let us say we want to check if C 2 is 0 the counter value C 2 is zero that means what when C 2 is 0 that means N 2 is 0 the number N has no counter value three as a factor in such a case right C 2 is 0 if and only if N is not divisible by three. So, can I check if the number is divisible by three or not yes by the simple use of the auxiliary counter remember I have now two counters in this two counter machines one representing the values N 1 N 2 N 3 in one go with such a number. So, I have this number N and I want to check if this number N is divisible by three what do I do I can keep taking out keep decrementing in this counter in groups of three. If I when I reach zero by then if I have completely taken out another bunch of three then I know this number is divisible by three right. So, for example, seven if I first decremented by make three decrements I will get four then I make three decrements I will get one and now this one I cannot as I try to decrement three times I will find that I will not be successful and the result will be the counter value will become zero before the you know we have managed to decrement three times. So, I know the number is not divisible by three and since it is not divisible by three therefore, C 2 is definitely zero actually we are not losing out anything because as you are decrementing three at a time you can keep putting the number of times you have been it has been possible for you to decrement three times I mean one one one and you know basically the result of N div three can be here and on hand you will know how many the remainder will be there. So, you can actually restore back this number. So, that is also nothing is getting lost in doing this checking increment a counter by one. So, let us see you wanted to increment this counter C 3 that means just multiplying the number by five. So, increment I can do decrement a positive counter by one is dividing the same thing essentially if I supposing I wanted to decrement this counter provided it is N 1 is non-zero and that is possible all I need to do is to divide the number get the number N div 2 because when you decrement N 1 you will have two here N 1 minus 1 and the old value old this new N prime is just old value of N divided by two and we have already seen how we can divide by a fixed constant remember these are fixed constants 2 3 and 5. You should note that this you know situation will not be possible if instead of prime numbers we had put something else for example, instead of five had you put four and for the representation so your representation would have been 2 N 1 3 N 2 4 N 3 and now we said that divisibility by two will tell me whether N 1 is 0 or not. So, suppose N 1 is 0 and yet the number will be divisible by two so that is why you need prime numbers whose you know powers are used to keep track of the contents. Now, to summarize what we have said is that the operation of three counters can be simulated by just two counters all the three counters of the original three counter machine their contents are represented in this manner in a composite manner in one counter and the auxiliary counter is used to do operations on the three counters to simulate the operations of the three counters we can do checking by zero increment decrement. So, therefore, the just with two counters we can simulate all the three counters therefore the two counter machine we can design which will be doing same thing as any given three counter machine and therefore, we say two counters will suffice. In conclusion, Turing machines can be simulated by counter machines with only two counters please remember that if you cut down the number of counters by one if you had one counter machine then we will have a very restricted form of a DPDA which is of course, cannot in general simulate Turing machine.


Fain art is something created for aesthetic or intellectual value and its beauty. It is rooted in drawing and design-based works such as painting, printmaking and sculpture. Presle Kevogo is a young fine artist who has decided to spread his wings and explore his potential in this field. To top on that, he is also a writer and entrepreneur. My art is fine art first of all but it's a mixture, it's a multimedia kind of drawing. I can use graphite, I can use charcoal, I can use watercolor, I can use paint and sometimes I combine a little bit of all of them so that I put them in one picture. Presle's art hails from within as it isn't inborn talent that he has nurtured since childhood with the help of his parents. I haven't been trained by anyone, this is something I was born with and it is a talent which I have been able to nurture ever since I was a child because I bought a lot of papers. My parents bought a lot of papers for me as well so I was drawing anything I could see that fascinated me, I used to draw just put it down. It didn't matter whether it was accurate at the time but I just wanted to draw because I liked it. Fine art encompasses different mediums such as painting, printing and sculpture that requires different materials which are rarely found hence the need for importation on Presle's side. These materials they are not easily found because most of them are not in Kenya. I had to import a couple of items and the ones that are available they are only found in specific shops like for example Textbook Centre. I can only find most of my things there. As much as the aesthetic function and beauty of an artwork is essential, time is also a factor in quality determination. In the art business there is nothing like set pricing, the price of an artwork is determined by the experience and expertise of the artist. That's the essence of art, art is all about beauty and it takes a longer time if you are a professional artist. I'm sure you've seen in maybe movies or maybe you have friends who are artists when they paint it's their skill they are selling you. It's not the materials in which they are buying. So the time it takes for them to produce that painting or that drawing is what makes them stand out. It's what makes them charge at a certain premium. So if you find someone who is charging you at a higher premium than the other, definitely they have something different to offer than the other party. In order to stand out from the rest, precisely invest more on details. My artist's interest is in something detailed, it's not necessarily restricted to African pictures. Well, you're lucky enough I've been able to carry one of my African portraits, actually it's a sold portrait, it's on loan. Other things which I'm able to draw, these are things which I research on and I just decide to do something different. I'm always attracted to something different, like I've done drawings on Aztec warriors, these are people who live long long time ago. I've done a portrait of King Sassis of Basha from the famous movie The 300 for the Spartans. I've also done a portrait of Ahindu Baba, that is a sage. And many other examples, all of these like I said you can find them on my Facebook page and you'll be able to see what I'm talking about. A business thrives on its clientele and the best form of marketing is through the customer's serve. It is therefore important for a business to ensure that it delivers the best output so a word about it can spread. This is therefore where the biggest market lies. The Kenyan market has potential. I specifically like one thing about Kenyans, they can make you go viral. So long as they see something and then someone shares it and then a couple of people like it, you can be famous in let's say two days. You remember Gideriman? Gideriman just shot up out of nowhere, he had it or something out of the blue. That is the same thing about art, so long as people love what they see, the marketing they'll do for you. The relevance of his artwork thrives on the fact that he is able to offer mentorship to others. This therefore creates a platform for creation of awareness to the public. I work alone at the moment, although I have one or two people who are mentoring, they are also artists but upcoming artists. First of all, most of young Kenyans are on Twitter, so it's hard shifting them from Twitter into the real world. But then again, I do with the little I can. Like I've mentioned to you before, I mentor two guys and both of them are artists. I've also joined a couple of groups online, Facebook. One of the groups is called Kenyan Art Wars. It has 3,500 members to date and we post work and encourage each other. Having been able to complete most of his previous projects, Corona has been quite a setback to his recent project and has also been a hindrance in selling of his work. I had started working just before the Corona hit us. There was a contract I was in the middle of negotiating with a well-known school and basically I was supposed to do artwork for the entire school. Where I'd paint cartoons, basically it was just a nursery institution. And in the course of December last year, I was also supposed to do a campaign. I'd paint letters and also colors on the hands of actors because they were campaigning for a certain movement, which they were unveiling in the course of December last year. I haven't been able to sell my artwork as I used to do before. So for now when I approach clients, they keep telling me please hold on until we see how this thing rolls out and then we'll talk to you later. And as I had told you before, there were two contracts I was supposed to handle. Both of them were artistic, but they had to be pulled on hold until further notice. So luckily like I said, I am a businessman, visa via writer. Writing is what is sustaining me right now and also business. Presley is a jerk of all trades and is still able to earn something little from his other sources as he awaits for things to get better after the corona season. Art is not a passion. Art is a strategy. I used to believe it's a passion but passion will only get you so far. Passion is fuel which runs out at some point. And I'll still go back to the example of the corona virus. Basically it has affected about 80 to 90% of companies, jobs, people have been laid off. And also for the self-employed individuals especially the young people, you find that you cannot do much business in terms of art. But even after things go back to normal, like I said before, the Kenyan market hasn't yet embraced art as a full talent earning kind of venture. So what I tell them is art is a good avenue. It is something to keep your demons at bay. But at the same time have about 4 to 5 sources of income if you are not employed in an organization for example. So that art can help you sustain yourself let's say when these other areas have been affected by something like this. A business is only as successful as how much has been invested in it. And this is not exclusively about money. In the art business invest more in attending and participating in galleries and art exhibitions which position you to reach your potential clients. This not only increases your chances of making yourself but also health position your brand. At your scale I believe we should come up together maybe have something like a conference for artists. The first of its kind in Kenya that is pencil artists. We should have something like a conference where we sit down and we figure out what we can do with our talent. To maximise unprofitability do not specialise rather be diverse to leverage on the extensive market. I like the way the youth of Kenya today are becoming more daring. People are venturing into graphics animation and also old school handwork art. There are very many categories of art once which we are yet to explore this garbage art. There is mural painting like I said. There is also wall painting. All kinds of arts. So should we continue with this let's say in the next 30 to 40 years I think people will have embraced the idea of art as a source of income and not just a source of income but also a source of expression. Because money aside it is what you have to show to the world that really counts. Just like most people have something they hold dear to their heart Presley is no exception in regards to his art. So this one is Venom and I drew it in 2018.  Where I drew grids and then I put in different elements that is the coloured pencils, paint, graphite basically combine all of them. So you can comfortably say Venom is the godfather of all the other drawings I've just shown you because this is what inspired all these other drawings. So on the face I've used watercolour paint parts of it. For the gums I used coloured pencils and paint and for the shirt and the t-shirt is a t-shirt. I used coloured pencils and charcoal pencils and for the beards as well as other areas I managed to use graphite pencils. The fine artist has been made with disappointments along the journey but just like an eagle he keeps soaring and flying high as the sky is never the limit. The Kenyan market has not yet matured enough to accommodate art as a full time job because first of all the market is very young and the purchasing power of the common mananji is not that strong or should I say it's not strong enough for them to buy your art on a regular basis. So if you're just starting out it won't be the best idea to major in it as the only source of income for yourself. All dreams are valid so don't shelve it. Go for it because you never know where it might lead you. Another thing I want to break this ceiling in which art has been associated with for a very long time. Art is not only restricted to pencil, it's not restricted to pens. Art can lead you to so many places because when you venture into art you might suddenly develop an interest in engineering, you might develop an interest in architecture because it's a branch of art. So it's just a matter of following the money, where is your talent leading you because the more you go deep into something the more you discover other areas. So the ultimate form of expression in my opinion is following a certain line, taking different categories and then putting them all together to form something unique that hasn't been seen before.