Okay. We're going to be working, again, with HTML5 Canvas. We're going to be loading some images. If you haven't already, this is part of the series. There should be an annotation up on the screen that will bring you to the playlist. If you haven't watched the entire playlist, I recommend it, but at least watch the last few on loading images. Now, on our first tutorial on loading images to the HTML5 Canvas, we did load multiple images, but we kind of did it by just doing the same thing over and over again. Today, we're going to work on creating a function that will load and draw the images for us. If you're going to be using multiple images, this is definitely a way to go. It will shorten up your code and organize a little bit better because you'll have things in lists. To get started, I've got Chrome open up here. As you can see, our page doesn't load anything just yet. Here's our code down here just to quickly review. We do have some CSS here that we added in for our Canvas image tutorials that just remove the margin and the padding of the body. That just removes any white border that's around our Canvas.  Then we've got our Canvas element, which we've called My Canvas with a capital C, but you can call that whatever you like within reason. Then we have our scripts here. Our script, we're going to create a variable, which is going to be our Canvas. That's going to be our Canvas element. We're getting it by its ID. Again, My Canvas. Just make sure these correspond. They are case-sensitive in correlation with each other. You don't have to have the capital C there, but if you have the capital C here, then you have to have the capital C there, or whatever letters you're going to capitalize. Then we're going to take that Canvas object that we just created. We're going to set it to 2D, and we're going to set that into a variable called Context. Let's go ahead and get started here. First thing we're going to do is right now I'm going to have two images. These first two images, this one that we've been working with of my daughter, which is inside the same directory as our script, and then this one of Tuck's dressed as Mario. Let's go ahead. What we're going to do is we're going to create an array with those URLs to the images, as well as giving them names, identifiers that we can select them from. Source equals, and the first one is my daughter, Ember. We'll just call it Ember, and then colon, and then a comma. It means there's going to be another one after that. Once again, this is the one that's going to be inside the same directory, so we can just give it a local reference of Ember. Actually, I think it's JPEG. The next one is the image of Tuck's. Here we're going to grab the URL for this, which is out on the internet. I'm just going to paste it in there. Someone's going to ask at this point, how did I copy and paste that? What I did, and this is just a little side note, doesn't really have to do with this tutorial, but I do get asked that sometimes. Most of you probably know this, but I'm surprised how often people don't know this, but I believe most Unix and Unix-like systems, Linux included, has two clipboards. You have your clipboard for when you do edit copy or control C to copy something, but also once you have something highlighted, it's automatically put into a clipboard. You can paste that by center-clicking anywhere else. The center-click is basically if you have a scroll wheel, you just click that down. You don't scroll, you just push the wheel down and it will paste. That's definitely handy inside the terminal. It's also just quicker than doing anything else, because anything else, you'd have to highlight it anyway. Once it's highlighted, it's already copied. That's a little side note for you. At this point, we're going to start creating our function. I'm going to say function. We're going to get the name of load images. I also do want to give credit to the website HTML5 of Canvas Tutorials. That's where I've learned pretty much all my Canvas stuff from in my tutorials are going to be similar to theirs. I just wanted to give them credit. We're calling it load images, but we can call it whatever we want. We can name the function whatever we want. Then we're going to pass it some information and set a call back here. Then we're going to set some local variables within here. We'll say one is images. This is going to be an array, and we're just going to leave it empty. We're doing curly braces there. Then we're going to set var load did images equals 0 and var num images equals 0. I am looking at notes because I'm Canvas stuff, so I'm using notes. If it seems like I'm reading something, that's because I am. Basically, what we're doing is we're creating variables and setting them 0 because we're going to use these to count the images in just a little bit. We're going to start counting at 0 because at this point we don't have any loaded. Next, we're going to do a for loop. We're going to say for var. We're going to create a variable called src inside our sources. What is our sources? I'll go over all this again at the end, but that's passed in here. I just realized I put source there. A little typo. I would have caught that later on. Actually, just be consistent. They could all be source or all sources. It makes more sense since there's more in them for it to be sources. When we call this function, which we'll do after we create it, we're going to pass it this list of images. That's what's going in there. That's what we're looking at here. We're going to look at each one of those and get its source from that variable there. I'm not sure if that made complete sense, but again, I'll explain everything better. We'll go through some stuff here at the end. At this point, we're going to start counting our num images. Basically, when we call this function, we're going to loop through each image and we're going to get the number of images. This will get us the number two, because we're starting at zero. For each image, we're going to add one. That's what the plus-plus there means. We're adding one. This is getting us a total count of the number of images that we've passed this function. We can change the number of images within this list here. That will then allow the function here to know how many images there are. Now we're going to create another for loop. Again, we're going to do src in sources. What src is going to represent here is the name that we've given our image. The first one will be ember, the second one will be tux, so forth, and so on. That's what src represents as we loop through here. Now we're going to say images, which is our empty array that we created up here. We're going to say we want to give it the value of the name of the image. We're going to say that we're going to create a new image. Then we're going to say images. Again, src.onload. Then we're going to say equals, and we're going to run a function. If you remember from our previous tutorials on this, we have to create an image to draw into our canvas. That's what we're doing here. Then when it's loaded, we're going to run a function. We're going to draw an image to our context, which is our canvas. The way it's knowing which image, it's basically giving each image its own name based on its label down here. I give it a little identifier there. Then when that's loaded, we're going to count the number of images, see if it's greater than or equal than the number of images. Then we're going to go ahead and get its source and draw it. Let's go ahead and do that again. I'll try to explain all this again at the end a little bit better. I'll say if, and then inside here we're going to say plus plus loaded images, which at this point is zero. We're going to say greater than equal to num images, which at this point would be two because we have added to it for each loop starting at zero. For each image we've looped through and added to it. Then this is when we're going to call our callback images. Then outside our if statement here, and actually outside that function, we're going to call images src.sources. This is where we're setting its source and how we know what the source is. We're going to say src.sources.src inside the brackets there. That will grab the source from our array down here. That is our function. Hopefully I typed everything right. We'll know if we get any problems. We'll check our console for errors, but we'll say now we're going to call our function load images. That's what we called up here. Again, you can call it something else, but then when you call it, you have to call the same name that you gave it. We're going to pass it src.sources, which in this case is our list of images here. Then we're going to say function images. Inside here is where we're going to do our drawing. We're going to say context.drawimg. What image are we going to draw? It's going to be the images that are passed and then the name. Images.ember. We'll give it a position of 0 comma 0, so it'll be in the top left corner. Then we're going to say context. Let's just bring that down a little bit so we can see better. Draw.img. Again, we're going to say images, but this time dot tux comma 0 comma 0. If we save that, and if I typed everything right and we come back to our html here and I hit F5, we get nothing. That means I typed something wrong. Either I put a comma or a semi-colon in the wrong place, I forgot a bracket, or I just misspelled something like before I was doing a source instead of sources, and so they weren't correlating. How do we find out what is wrong? Well, the first place we should start is if you're in Chrome, just hit F12 and it will bring up your console, like so. If you're in Firefox, it does have some built-in console, but the Firebug console is a plugin that's also very handy. But here it's saying it's caught two errors. See right there it says, I num images. I put an I at the beginning there by accident. That was a typo on my behalf. It says it's on line 28. If we click over here, it actually brings you right to that line. But come back here into my editor and I can go to line 28. Right there. Save that. Refresh. There we go. Good thing I only made one little typo there. And of course the order it draws the images does make a difference because what's drawn second will be placed on top of the first thing that's drawn. So if we have three images, the first image drawn will be back, then the second image will be drawn on top of the first, and then the third will be drawn on top of the second. So now that we've done that, let's add in a third image. So I've already done a Google search, found this one of Tux's Rambo. I'm going to copy its URL here just by highlighting it. And I'm going to just add it to this list. I'll call it Rambo colon. And then paste it in there. Now, because we had another one need to add a comma. Each item needs comma. Each item needs commas in between them. So basically all except for the last one will have a comma after it. And then down here I'm just going to quickly to save time. Paste. So we're going to say context. Draw images. Which image are we going to draw? I'm going to draw the Rambo one based on its name right there. If I save that and then remember that I need to put a comma there. Then save it again. Come back here. I'll hit F5 to refresh. Oh, sorry. Go to our page and hit F5 to refresh. It drew that. And again, since it was drawn last, it's drawn on top of the other Tux. You can kind of see the other Tux a little bit behind him. Let's give him another position. We'll move him 400 and 200. Save that and we'll refresh. And you can see he's been moved over 400 pixels and down 200. We can also move this Tux. We'll move him over 100 and down 200 so he'll be on the same plane as that guy. So it looks like they're standing next to each other. So let's quickly review all this code. So again, we have our canvas. We create our canvas element inside our script here. Now we have our function and we have our source list and then our load images when we're calling the function. So let's start here. Again, we have a list of our images and we're going to do with that list what we're going to call our function which is up here but we're calling it here. We're putting in this list. It's going to run that function and then retrieve some output with images there. So let's go see what it's doing up here. We're saying we're going to pass it that source list. It's called sources. Again, an empty array. Two variables set as zero to count stuff. Now that we have num images set to zero for each image we're going to loop and add one. So in this case there's three images we're going from zero one, two, three. So we know there are three images. Then we're going to loop through each image again at this point and we're going to say images. Which image we're going to pass it? Well, this one's ember and then tux and then Rambo. And we're going to create a new image based on that. So basically each image will have its own name.  Then we're going to say well we're going to load that image and run this function. And it's going to check what is the loaded images, the number of images loaded equal to or greater than the num images. If it is equal to or greater than, then we're going to do our call back passing in the images. And then what we're going to do outside of that is, so if that's basically saying at this point we're done go back to down here and draw the image. Now before it's done, if we haven't loaded all the images we have to say okay, well that image that we just put in, let's give it a source. So sources is going to be basically look at each image and look at its URL here. So it's going to loop three times and then on the fourth loop it should say oh, we have now loaded all the images. Let's do the call back come back down here, pass it images. So now those images, which image and it will just draw each one. And again here we're just giving it positions. Now of course I always recommend typing out code by hand when you're learning, really all the time because it always just gets you better at what you're doing. But I will post this in my Pastebin account. If you go to pastebin.com and my username is metalx1000 you will be able to find this. You can also go to filmsbychrist.com. That's Chris of the K. There's a link in the description. That's my site. There should be a link somewhere that says scripts. Right now it's in the top toolbar. But my site might change in the future. And that will bring you straight to here when you click on that. And you can see all the scripts that I've uploaded. And we have a list of all the HTML ones here that we've gone through already. And of course this one will be there. It will be named like multiple images HTML5 or something like that. And you can always copy and paste it to test it. But I recommend to actually type it out when you're learning. But this image of my daughter is not going to be in that script since it's an image on my local machine.  But this code just as it is will go up on the page. So if I run it again now that I've removed those two lines for that image and hit F5 you can see it still runs. It just doesn't place the image because it no longer exists. So if you're just doing a thing with one or two images, writing out this function might be a little more typing but definitely keeps things more organized. And really once you have more than three photos this is going to start shortening your code. You can have like a hundred photos in here. And all you have to do is add them to the list and then add them to your little draw function here. So that's it. I hope you're enjoying these tutorials. Now that we've done some loading images and a few more tutorials on the basics of HTML5 canvas then we'll move on to advanced stuff and then we'll start moving into other tools for 2D stuff and then eventually 3D stuff. And hopefully by the time I get to those tutorials I'm a little more knowledgeable on the 3D stuff because I've played around with it a little bit and I'm so happy with what I've learned so far and I think we're going to do a lot of fun things. And again because we're doing it in HTML5 and pretty much all modern operating systems can run HTML5 and most modern browsers are at least catching up because it's not the standard yet but it will be HTML5, not that everyone follows the standard, but we'll learn how to create things that will run on pretty much any device phone, tablet, Android, iPhone, Windows 8, mobile, Linux FreeBSD, any modern operating system will be able to run what we are creating, at least in theory. So I hope you're enjoying these tutorials, I'm enjoying making them, I'm enjoying learning. Visit FilmsByChris.com, that's Chris of the K, there should be a link in the description and I hope that you have a great day.


Thank you everyone. I'm presenting a open-source tool on sandboxing for enabling safe installation of untrusted open-source packages. I'm Ashish. I hold a PhD in cybersecurity from Georgia Tech, and now I work at Oslate, and we're building tools to mitigate open-source supply chain attacks. So what are these attacks? So in the last couple of years, we have seen bad actors publish malicious packages on popular package managers such as PiPi, RubyGems, and NPM, and these attacks have been increasing every year. So how do we defend against such attacks? So security is a shared responsibility, and we must all do our part. And there are multiple measures that I think we have talked about. For example, enabling two-factor authentication to stop account hijacking attempts. Namely, name scoping to stop dependency confusion attacks, and we've talked about code signing provenance. However, these measures fall short. For example, our discriminant maintainers, like we saw, a recent protest wear attack. They can abuse their own package. So they can still propagate malware. So this figure is from Salsa, a supply chain security framework from Google, and it says that Salsa framework cannot protect against compromised packages. So we need additional security measures, or we must thoroughly analyze the code that we are using, especially if it's untrusted third-party. However, this is easier said than done, because every package can have hundreds of thousands of transitive dependencies, and reviewing everything manually is just invisible. So there are open-source tools like package that can semi-automate this, to some extent. It can look for several risky attributes, such as if the dependency is old or vulnerable, number of dependencies, any risky APIs. For example, is the package trying to access your file system, your keys, or trying to talk to a server that's remote? If the package repo is available and the code matches with the repo or not. However, a sophisticated malware can still find a way. For example, there was a recent academic study that said 99% of malicious NPM packages that were found at least used one pre-installed hook. What that means is that a malicious package can behave differently in different environments, different operating systems. A different CICD environment can behave differently in production, can trigger at a later time, and can hide itself in a bit analysis. So that's why we must apply security in layers. So an additional layer is sandboxing layer, and this can enable a safe installation. At least we can sandbox the install step of dependencies. So we have built this tool called package sandbox. It's open-source hosted on GitHub under oscillating, and it can basically detect and stop any malicious activities before it can happen. And it's fully configurable. It can take custom firewall rules. For example, you can specify that package installation should only go to rubygems.com or npsds.org. You can specify what file system directories should be touched. So for example, if you want to prevent SolarWinds like attack where the code was overwritten, you can specify that do not write current directory. It can also monitor processes that are being created. For example, if a package is trying to spawn a pseudo shell, you can be detected and blocked. So let's see the sandbox in action. So in this case, what we are doing is we are trying to sandbox installation of a rubygem called overcommit, and it's the same command. It's just you need to add package sandbox before the actual installation command. And what it's going to do is it will do the same installation steps. It will get the package star ball and it will install. But at the end of it, it's going to provide you with data on what the package installation step did. So what URLs were contacted, what servers were contacted. And it will block anything that you have not listed. You have not allowed in your custom firewall rule. And it will also give you a summary of files and changes. So what files and some changes were made. And it will allow you to either commit or discard these changes. If you discard the package will not be installed. And it can also fake network requests. So the package installation could still succeed and not cause any actual outbound requests. So the question is why not containers or VMs? Well, they are built for different purpose. So for example, they have this host versus guest notion. So if you install a package in a container or a VM, you're installing in guest, and then you need to copy it back to host. Also for compatibility, the host file system and the guest file system must exactly be the same. Otherwise, it will cause incompatibilities. For example, native packages or packages, Python packages that have wheels. And these tools also require super user privileges. That means you're increasing the attack surface. And in your CIC environment, you would need Docker in Docker or nested VMs to enable this. So package sandbox tool fills the gap. It intercepts all system call requests and it'll rewrite the argument at runtime so that the file system changes are layered on top of the host file system. So that means package installation step gets exact replica of where you want the package to be installed finally. And at the same time, it'll layer those changes. So it's copy on right. And no root privileges are required. It uses ptrace. So you can enable harden CIC pipeline with package. So you have to get a GitHub action. It can also audit as well as sandbox the installation process. So it'll point you end of it, literally, you know, comment on your PR and point if there's any risky packages or dependencies. For example, in this case, you know, we found a vulnerable one and a one that needs review because it communicates with Excel network. Perhaps it's supposed to. So but it just says that you need to review the code. So it will reduce thorough manual wetting to a couple of code glances. That's it. Thank you so much. And the package source code is hosted on GitHub. Love any feedback? Thank you. So we are tracing this process, installation process and all children processes that are spawned as part of this parent installation step. We intercept every system call request. So every file system request, every network request is intercepted. If you build with a container, I haven't tried. I think it should work, but I haven't tried. But I think the support can be added. If you're asking if it can log all system call requests so that you can review and is that am I understanding correctly? Yes. So you can have your allow list in your firewall rules and it will only allow those requests. And pretty much you can add some sort of a destination to that. Thank you so much.


So pretty much all the information in this video comes from a book called The World of Ice and Fire, which was a book written by George R. R. Martin. And it's really cool because you get to learn all about all these cool places and cities that George R. Martin didn't really have time to go over in Game of Thrones, but you still get to learn more of the lore and history of the Game of Thrones universe. If you want to check it out, there's an Amazon link below. And while you're down there, why don't you go ahead and hit the subscribe button. Game of Thrones, one of the most popular TV shows of all time and easily, one of the most critically acclaimed, garnering 132 Emmy nominations and winning 47 of those awards, including Outstanding Drama Series for three of their seven seasons. If it wasn't for Breaking Bad, they probably would have won seven for seven. Like your typical fantasy, it takes place in a medieval world, with knights, kings, princesses and dragons, but much, much more dark and twisted. In the TV series, pretty much all of the action happens here, on this tiny continent called Westeros. But what many people don't realize is that Westeros is only a small portion of the known world. This is the known world. It's wide and vast. Many think it even rivals that of Tolkien. Unfortunately, we don't get to explore or see much of it in the TV series. Granted, we do get to see Daenerys and Arya in Essos a couple times, but never in the further East regions. With a world so wide and vast and with a TV show so popular, why aren't there any Asian people in Game of Thrones? To preface this, yes, I do know that Asia doesn't exist in Game of Thrones, but for the intent of this video, the word Asian will mean characters and countries that were obviously based on Asian culture, history and appearance. So back to the question, why are there no Asians in Game of Thrones? Actually there are. Given that there were very few and most were actually background characters, but the only character with any significance at all is this red priestess. Found in Season 5, preaching that Daenerys is the savior. And this priestess is the only Asian character with any lines in the whole Game of Thrones series.  The world of Game of Thrones was built to resemble our real world very closely. As you probably noticed, Westeros is based on the island of Great Britain and even looks just like it, just rearranged a little bit. King's Landing is England, the north is Scotland, the region is France, Dorne is Spain or Portugal and Valeria is a tribute to ancient Rome. So this priestess, where does she come from? She comes all the way from this empire on the east side of the world called Yiti, the golden empire of Yiti, located on the eastern region of Essos, east of Carthens and the Bone Mountains. To the south lies the Jade Sea and Yiti of course is obviously based on ancient China. Yiti is a large and diverse country. It is described as being a realm of windswept plains, rolling hills, jungles and rainforests, deep lakes and rushing rivers and shrinking inland seas. The land of a thousand gods and a hundred princes, ruled by one god emperor. As the name suggests, in ancient days the emperors were treated like gods, they had power greater than any western king, wealth that exceeded even that of Valeria at its height and armies of almost unimaginable size, the great empire of the dawn. It was ruled over by the first god emperor, known as the God on Earth. For ten thousand years, his rule reigned until he ascended to the stars. Dominion was then passed to his eldest son, the Pearl Emperor and he ruled for centuries yet every preceding emperor's reign was shorter and more troubled than the one preceding it. For wild men and baleful beasts pressed at the borders of the great empire, lesser kings grew prideful and rebellious and common people gave themselves to avarice, envy, lust, murder, incest, gluttony and sloth. When the Amethyst Empress was crowned, her envious younger brother cast her down and slew her, proclaiming himself as the bloodstone emperor. And thus, beginning a reign of terror, he practiced dark arts, torture and necromancy and slaved his people and took a tiger woman for his bride. He feasted on human flesh and cast down the true gods to worship a black stone that had fallen from the sky. That ushered in an age of darkness called the Long Night. Because of their evil, it is said that the gods came forth to rot their punishment on the wickedness of men. And eventually, the empire crumbled. After the fall of the great empire of the dawn emerged the golden empire of Yiti. Since the Long Night, there has been eleven dynasties. The cities are far famed as well, for no other land or country can boast so many. It is said none of the cities of the west can compare to those of Yiti in size or splendor. Not King's Landing, not Highgarden, not even Valeria at the height of their power. The emperor sits in a palace larger than all of King's Landing. Imagine that for a second, not the city it resides in, but a palace with a larger square area than the biggest city of Westeros. To quote adventurer Lamas Longstrider, even the ruins put ours to shame. Its legendary wealth is such as to allow its princess to live in houses of solid gold and dine on sweet meats, powdered with pearls, and jade. There are many parallels with ancient China and Yiti. In fact, Yiti actually means one body in Mandarin. Much like how Asia is separated from Europe because of the Ural Mountains and the Himalayas, Yiti and the surrounding regions are separated by the Bone Mountains, the largest mountain range in the known world. To the north is the plains of the Jogosnai, a race of mounted warriors said to have shared ancestry with the Dothraki.  The Jogosnai are shorter than the Dothraki and have much more Asian features. They are bow-legged and have pointed skulls, which come from biting their skulls as babies. They ride these strange animals called sources, which are hybrid of horses and zebras in the Game of Thrones world. They are loosely based on huns or the Mongols of ancient times. Like the Mongols, they are always raiding and fighting the cities of Yiti. Over the past 2,000 years, the Jogosnai have sacked a dozen Yiti cities, a hundred towns and farms and fields beyond counting. Many emperors have tried to defeat the Jogosnai, none have succeeded. To the north, these are the Five Forts. Massive fortresses made of black stone, said to be almost a thousand feet tall and can hold 10,000 men. For comparison, the wall in Game of Thrones is said to be 700 feet tall. The forts were built by an emperor to protect Yiti from the Lion of Night, an ancient god and his demons, but also from raiders and enemy armies. We can assume that this is a nod to the Great Wall of China. To the south of Yiti lies Leng. The verdant isle of Leng is home to 10,000 tigers and 10 million monkeys. Leng actually used to be part of Yiti up until 400 years ago, when Leng became an independent nation. They speak a dialect of the same language, pray to the same gods, eat the same food and follow the same customs. However, they are ruled by their own god emperors. In addition to the people of Yiti's descent, Leng is home to native Lengi, which are said to be the tallest people in the known world, sometimes growing up to 8 feet tall. Up until Yitish rule, Leng had been an isolated country, very much hostile to outsiders, closing with borders for centuries. Many people say Leng is based on Japan, but judging by its history, it seems to resemble Taiwan's history very closely. Like China and England, Yiti is actually thousands and thousands of miles from Westeros. Yiti is so far away from Westeros that encountering a Yitish people in King's Landing is as unlikely as encountering people from China and Medieval England. Medieval long distance travel was quite limited. Add that to the fact that if you go by land, you would have to go through Bone Mountain and then through the Dothraki Sea or the Red Waste. Good luck. Then you will still have to walk thousands and thousands of miles to either Braavos, Pentos or Mir. By sea, it isn't that much easier, so it makes complete sense as to why there aren't too many Asians in Game of Thrones. They're on the other side of the world. In our current day, since the Azure Emperor Bukkai, yet far to the east, past the legendary mountains of Morne in the city of Carcosa, dwells an exiled sorcerer who claims to be the 69th Yellow Emperor from a dynasty fallen for a thousand years. And more recently, a general named Po, called Hammer of the Jogos Knight, has given himself imperial honors naming himself the first of the Orange Emperors with the rude, sprawling garrison city called Trader Town as its capital. Each of these three men declare that they have the claim to the throne and are willing to go to war to become emperor. Wait, wait a minute, this story sounds really familiar. The three separate kingdoms going to war to become the Emperor of China, I mean Yi Ti. Much like how Game of Thrones was inspired by the War of the Roses of the 15th Century, it seems like George R. R. Martin is setting up a story in Yi Ti, very similar to the romance of the three kingdoms. The three kingdoms was a war in China from 220 to 280 AD. China was in a fractured state, where many warlords were vying for the Emperorship. Eventually, it came down to three separate kingdoms, all fighting to become emperor. It went down as one of the deadliest wars of all time, with 40 million deaths. Second, only to World War II, it has been the subject of many TV shows, movies, and even video games. I mean, how amazing would that be? Romance of the three kingdoms, but set up in the Game of Thrones universe. A much darker and twisted dynasty warriors. And if Leng, or any nearby country is set up to be a parallel to Japan, we could potentially get warriors, samurai, ninjas, sorcerers, and monks all in one insane dark story. Seeing how it's been 10 years and winds of winter still isn't finished, which is the next book in the series, it's kind of doubtful that this story will ever get close to ever being made. But, Martin already has the universe set up for it, so if HBO or whoever ever wanted to make a spin-off series, they're good to go. Which I think is really exciting. If you want to check out the World of Ice and Fire by George R. Martin, there's an Amazon link below. Also, hit subscribe, hit that like button, and remember, John should a pet ghost. I mean, why didn't he pet the dang dog?


Good morning, good afternoon, or good evening, depending on where you are. We're very happy that you can attend this session. And today, myself and my co-presenter will talk a little bit about the Harper project. So this is supposed to be an introductory session. It's going to be fairly light. And we'll give a high-level overview of the Harper group registry and what it is, why you might need it, and the current status of the project, some of the things that we worked on for the last couple of releases. And then there's also a deep-dive session where our engineers will go into more details on some of the specific features that are coming out, about the 2.1 release, the upcoming release. And then we have a demo prepared for you today as well. And we'll leave the last 10 minutes for Q&A. So a quick introduction. I'm Alex Xu. I'm a product manager in a cloud-native team at VMware, leading the Harper effort, sort of trying to be responsible for trying to understand the requirements around the registry, driving the roadmap, collecting feedback, and making sure we're constantly improving and seeing sustained growth within the community. And with me today is my co-presenter, Stephen Rin. Stephen. Hi, everyone. Nice to meet you. And welcome to join our Harper instruction. And I'm Stephen Rin. So I'm working for Harper as an engineer manager in VMware. So I'm mainly responsible for developing the feature and managing the release. In the same time, in VMware, I also manage the Tanzu Kubernetes Grid Equation product. All right. Thank you, Stephen. So what is Harper? Well, Harper is a trusted cloud-native registry that can store, sign, and scan content. And so the registry is basically just a place to hold hosts and manage our artifacts. And so when we started this project, we set out to build an on-prem registry leveraging the Docker distribution, which was the fact of standard for storing content images at the time. But we also wanted to address on the issues that we came across while using Docker Hub and some of the other alternatives. And then over time, we've added more and more services and features to it, like cycle management features, security features like scanning and signing. And so our mission right now is still to be the best cloud-native registry for Kubernetes. And we started support for Docker images and then expanded to Helm charts in the 1.6 release. And now with OCI, which is the main theme for the 2.0 release that I'll talk about in a little bit, we can support any OCI-compatible artifacts. So this is a quick timeline of the project. The biggest announcement this time around is that we have officially reached graduated status in CNCF and becomes the 11th project in CNCF to do so, along with projects like Kubernetes, Container and Gain, Helm, more Prometheus. And so you can see that we started this journey back in 2014. So we put a lot of work and attention into it. And so we're very happy and we're very proud of what we've accomplished, but we could not have done this without everyone in the community, including all of you guys on the call today. And the community plays a huge role in helping us understand, test, giving feedback, and sort of driving the roadmap with us. So we're very appreciative of everyone's contribution here. And in the project we each graduated status means that it's hit a certain level of maturity, but it's really the potential and the roadmap that drives this decision. So this is a quick overview of the various pieces or capabilities that make up Harvard. And we'll just go over a couple of these real quick. First thing is access control. You can use local DB, LDAP, or OIDC to connect to Harvard and manage your users and their permissions into Harvard projects. If you're not familiar with Harvard projects, think of it as like a namespace. It's a unit of tendency and has its own set of repositories and images that are completely isolated from each other. We also have robot accounts for service accounts, CI, CD type of scenarios to automate the pushing and pulling of images. And you can configure, reputation's referring to the ability to configure push-based or pull-based replication policies to and from other registries. So that could be a harbor. It could also be something like Docker Hub or Quay or any of the other popular SaaS registries like GCR, ACR, ECR. And then we have the ability to scan images from within Harvard, leveraging popular image standards like Clare, Encore, Trivi by security, and a couple of others. And then once you have those vulnerabilities, the list of vulnerabilities discovered from the image scans, you can actually create security policies around these. So you can create a policy that says, hey, this allow any kind of image pulling on images with certain vulnerabilities. You can also sign images, leveraging Docker Content Trust, which comes with Harvard, and likewise create image pulling policies based on the signature. So for example, you can say something like, prevent any unsigned image from being deployed. We also support managing Helm charts. So previously, this was done in the third-party extension that we had added called Charmysim. But with the 2.0, you can now push these directly to the registry, and they sit alongside your container images. So we have a single web console that you can do everything for managing your artifacts, your users, and your policies, running spectrum tasks like garbage collection, and everything you can do on UI you can do through an API. And finally, we have a couple of deployments with Harvard. So there's a document goes format. You can also deploy Harvard as a Kubernetes cluster using our Helm chart. And Bosch is another container orchestrator that's used very heavily in Cloud Foundry. So this is an overview of the latest Harvard 2.0 architecture makeup. You can see that we're still based around the document distribution.   And since 2.0 sees support for all these additional cloud native artifact types, there are other clients that different artifact authors that build for interacting with the registry. So for example, Aura is one such client that's very popular for pushing a lot of generic OCI artifacts, like OCI indexes. You can also push Helm charts and push Open Policy Agents. Chart Museum is still here, so you can post them in Chart Museum, as well as in the top distribution. But we do have clients that advocate Chart Museum in the future. And on the right hand side, we have a list of supported scanners. Scanners are added in out-of-treat fashion to Harvard for pluggable interrogation services framework. And we talked a lot about this in the 1.10 release, but we do have some changes related to the default scanner that I'll talk about in the later slide. And finally, we've expanded the list of replication targets. So you can replicate not just to Harvard and Docker Hub, but a lot of the other assets registries as well. And you can replicate all these other artifacts now beyond just container images and Helm charts. But obviously, that also depends on the supportability of these artifacts on the target registry. So if you've seen the CNCF announcement in the release block around Harvard 2.0, Harvard 2.0 was all about Harvard becoming an OCI compliant registry. And so we should talk a little bit about what OCI is before we talk about what it means for Harvard to be an OCI compatible registry, an OCI compliant, OCI capable. So following this picture, we started with Docker on the left-hand side, or the Docker distribution to be more specific. And the Docker distribution is just essentially some content store for storing your Docker images. And so Harvard as a registry built around Docker distribution is just some HTTP API backed by that content store. And so up until very recently before the 2.0, the only artifacts that you can push to Harvard and manage on Harvard over container images. Yes, you can push Helm charts, but like we said earlier, those were managed through Charm Museum separately from the images. And they didn't get the same set of features like tag retention, tag immobility that container images have. And so OCI, the Open Container Initiative, is a group that came along to define specifications around format, runtime, and distribution so that a broader set of cloud native artifacts can get the same features as container images. And it wanted the distribution to be able to deliver a registry that is secure, cross-layered, or layered, and cross-reconstable. And so it took the Docker lead 2.2 image spec as a starting point, and it created its own specifications around image format and image runtime. And so what this picture is attempting to capture is a little bit of that process or that history where OCI formalized these specs around image format and image distribution. And that work was merged back into a Docker distribution so that it fully supports OCI images. And so Docker distribution, in turn, Harvard can now support hosting all these other cloud native artifacts that we've heard so much about in these conferences, such as Helm charts, CNAP, Open Policy Agents, senior layer. So the second icon here is supposed to be a CNAP, what's known as a cloud native application bundle. It's another application deployment-oriented artifact that's worked on by the guys over in Microsoft. So being able to host Docker Manifest List is one of the things that came out, this support for OCI. And the Docker Manifest List is something that has existed for a while but was previously supported in Harvard. And the Manifest List is essentially just a packaging of Manifests. As you can see in this picture, we start with the Manifest List, which is itself a shell digest, and it's acting as a pointer to all these other images that are each built for a specific architecture. And so it's holding these together in some way and that's what allows you to use the same image name for all these different images built for different architectures. And so just try to keep this in the back of your head that there is this index structure called an OCI index. And we'll come back to this later in the demo. And so Docker Hub is actually a really good example of something that is OCI compliant. And probably the first registry that's OCI compliant. And it can fully handle the Docker Manifest List that we just talked about. In fact, pretty much all the official images that you see on Docker Hub today are using the Manifest List, allowing for multiple platforms to be supported using the same image name, image tag combination. And so here, shown here, is the busy box image with tag latest. And you can see that it's referenced in multiple shell digests for different architectures. So you have Linux, you have ARM, you have MIPS, and you even have different variants of these architectures. And so when you do a Docker pull busy box from Docker Hub today, it will actually fetch the version of that image that matches your client. So unless you're pulling specifically by digest, if you pull by tag, Docker Hub will responsibly fetch the right version of that image. And so that's the experience that we wanted to deliver with Harvard as well, that users can push and pull Manifest List, if they can manage these as a whole, but also manage the images within individually. And so that's also just one use of OCI index, this multi-architecture image on Docker Hub that we just looked at. But there are other artifacts that are leveraging this that are shown here. And so here we're looking at a project within Harvard, looking at a specific repository within that project. And you can see that we have a container image, a Helm chart, a cloud native application bundle, and another Docker image on the same project recognized by their logo on the left-hand side. And so we put this here to sort of draw contrast with the one point X version of Harvard where you only had container images, nothing else. But now you have all these other artifacts that you can manage in the same project. So that's really the biggest piece for the 2.0bies. Now, the other work we did for 2.0 was replacing Claire image scanner with Trivi, which is another open source image scanner by a company called Aqua Security. And Claire has been our default scanner and since probably going back to the first version of Harvard, but we started looking at other scanners because users have been asking us, I've set up such-and-such scanner, I've paid for such-and-such scanner, and can I get that to work with Harvard? And so, you know, in the previous one point X version that we had done a lot of work to sort of open up those partnerships with different image scanners through our plug-in interrogation services framework. But this is sort of taking things one step further with regard to the embedded default image hardware scanner. And so very, very simply, we lend it on Trivi because it's simple, it's comprehensive, it's fast, and it's accurate. It's also easy to set up, there's no need to manage a DB instance separately to run some darkness mode. Trivi also has a wider coverage for scanning different operating systems and application dependency managers, a lot of which are listed here, but there are more. And we found Trivi to just be superior in conducting deeper scans and capturing more vulnerabilities across all the different operating systems that we've tested, including DB and Ubuntu, Susie, Voton. So please check them out if you haven't, and I believe they have some sessions at this conference as well. So that's 2.0 in the nutshell, and I just wanted to spend a quick few minutes on giving a preview of the 2.1 upcoming release. And the first one I'll talk about is proxy cache, which is the ability for hardware to act as a pull-through cache for another remote registry. And we can call that registry the target or the upstream or the remote. And so this is useful in situations where you have Docker nodes that either have limited connectivity or no connectivity to that target registry. And it could be any number of reasons, right? The security or compliance reasons or it could just be pure connectivity issues and limited egress options. And so Docker Hub is a really good example. And that was the case that was brought to us, that was the most often raised to us.  And so hardware as a proxy cache is meant to address this very problem. And in this case, it means that hardware will serve. So if you have a hardware deployed, it will service the middleman to pull the images from the remote registry that you're trying to hit, cache it locally and then serve it to you. And so it's much faster and it minimizes traversal over the network, right? It prevents you from getting IP banned. And what it do this is to create a project in Harbor. It's, if you're familiar with how you create a project in Harbor, it's the same process except there's an option to enable it as a proxy project which requires you to enter the target registry endpoint and the credentials. And so when you wanna do a Docker pull from that remote registry, you can instead do a Docker pull from the proxy project instead. So you will have to modify your Docker pull command and your pod manifest to hit that proxy cache instead. So I mean, in the interest of time, I'm gonna just give a one or two some summary of this. I'm not going to too much detail. You guys can learn about this in the deep dive but essentially we're improving the garbage collection so it's not blocking. So you can still push and pull and delete images while it's running. This is not the case right now because the registry is put into read only mode. And then we also have an integration with PTP providers like Rupert Kraken and Alibaba Dragonfly. So there's gonna be a way to sort of, there's an action called pre-heating which moves the images from Harbor to the PTP side where it can be geo-distributed to hundreds or thousands of nodes in a more effectively efficient way utilizing their PTP distribution efficiency. So last thing, you know, that's the 2.1. It's coming out in the August. Please give it a try and appreciate any feedback you have when it comes out. Just final word about the community. The community is doing really well and we appreciate everyone's contribution whether it's raising requirements or fixing bugs, submitting PRs or doing code reviews which is attending the community meetings and attending this could become conference for example. So we're at 12.4K stars and within 20 contributors and lots of companies are using Harbor or have partnerships with us. All right, I'm gonna let Sieben do the demo because I think we're at almost 20 minutes. So I'd love to ask Sieben. Okay, thank you. Thanks Alex, let's share my screen. I assume everyone can see my screen. So yeah, as Alex introduced, so we have several major features given interest of the time. I'm going to demonstrate the two major features from $2 and $2.1. So the first one is about the OCI support we provided in $2.0. So as Alex introduced, so for the $2.0 we have introduced OCI artifacts support. With this feature, we can not only manage the images and we can also many hem charts, scene and bundle and other formats which follow the OCI distribution standard. Yeah, first let's have a demo situation on the manifest list. As we know, manifest list is a feature that which can store all kinds of different architecture images for a single repo. So I will demo how to upload a manifest in through those steps. First, we need to create a manifest and Docker has provided a manifest command which allow you to create a manifest and you need to specify the target URL as well as the images which belong to the manifest list. So here I have included two images. So one is for the AMD architecture images and another is for the ARM architecture images. So once we have created manifest, we need to annotate those two separate images as different architecture. So once this annotation is done and we can use Docker manifest push to push to the harbor. Yeah, so once we have pushed to the harbor and we can check our UI, look at what the UI functionality we have provided in harbor. So as you can see there's a hallowart manifest uploaded and for the manifest there's a folder icon you can click in and see what the inside the manifest images are. So yeah, as you can see, the two images one is the ARM architect and I am the 64 architect. Yeah, so next I'm going to demo is that so with OCI architect support we can also upload the hamchat. As they know in harbor 2.x they are supporting user to upload hamchat and many have chat through the chat museum. So in ham three there's experimental feature user can upload the hamchats to the OCI compatible register and this is what I'm going to demo. So yeah, as the command shows that every time you need to set this experimental tag before you run any commands for this experimental feature as I have just showed we have two hamchats and I tagged before the demo so we can use hamchat push to push this to harbor and once it is pushed and we can check on the UI in harbor portal and see the hamchat is uploaded and we have a ham icon also attached to with this artifact. So if you click into this hamchat and we can see all the additional information introduction of this hamchat this is the themes that we have provided in the chat museum. Yeah, so in the same time you can also pull from harbor about the hamchat that you have uploaded and this is just the demo of this. So yeah, so in the same time we are not removing the chat museum feature because there's also existing ham two users who cannot upload charts to the OCI registry still consuming chat museum. So we keep this feature in 2.0 and 2.1 and we hope that eventually we can remove this dependency and we can store charts all using OCI registry. The third I would like to demo is that cloud native application bundle scenario. So as we know, so in cloud native world it's not just images, right? We have a chart, we have all we have seen them bundle we also have OPA bundle we have other like YAML file we need to upload actually for the OCI support and we can manage all those cloud native artifacts. This is demo that use the CNAP to OCI command to upload a CNAM bundle to harbor. As we can see this is a sample CNAM bundle JSON file. So once we have two nub load and we can see from the UI there are two, two artifacts we need to send bundle will be uploading as we can see that for the CNAP icon and we can click in through this folder icon we can see there's one image uploaded and also there's a file uploaded. Yeah, let's quickly go through the power of the OCI formats is that so besides any official formats we can also upload a top file or folder so the OOS command line to manage the other OCI artifacts. Here I'm going to show you that use the OOS to upload a tar file. So you can simply use the OOS push giving a target URL and visit the location of your current target file. And once you have uploaded and you can also use OOS, yeah, also upload a folder. So once we have uploaded, we can check the UI portal and we have above this artifact and we can also pull it down to our machine. So I'm just changing to different directory and remove the previous downloaded version and I will use pull command to pull the target file artifact as we can see. So when you pull the OOS artifact and all OOS will automatically change the format you have uploaded it before. So you will get a folder and you will get a target file. Okay, as Alex mentioned, so besides the pull and push so there are other features like scanning, replication and the tank retention. All those functionality can work very well with the new OOS artifacts. Yeah, I'm just showing the scanning works. So I think, yeah, with that let's move into the POS cache feature. For the POS cache actually we are solving two problems. One problem is that when you have isolated environment probably you just need to config the harbor as your proxy to pull image from outside your isolated environment and then have a cache in this pull the images for the first future use. So let me go directly to how the user can configure this. So first, user need to create registry endpoint. This registry endpoint is tell harbor where you would like to pull your images from. So for this demo I'm currently choosing Docker hub registry endpoint. As you can see in the previous list we are almost swatting as many replication registry endpoint currently support as possible. So once you have config this Docker hub registry endpoint what you further need to do is that you need to create a proxy cache project. So you create a project and what you need to do is that you check this POS cache feature and fill in the endpoint you have just configed. And click okay. Yeah once this is done and you can see a new project is created and you can change to the command line to push images. So here as you can see I have, yeah I removed the previous download image and I will pull a new images. So this POS cache projects. So yeah beside red is I can also pull the MySQL. I can also pull hello world. Whatever you have in your Docker hub you can pull it. Yeah so once you have pulled it successfully you can see new repository is cached in harbor in this POS cache project. Yeah I think that's all my demo. We give an intro to the time and for the other features we have introduced please join our deep dive session so we will introduce more about other features.