If you guys want to be with a chance of winning this resurrection is to emblem simply drop a like on the video and leave a comment what's going on guys today I am back with another destiny 2 video and today I got a little bit of information for you guys now later today we will get the full reveal trailer for destiny 2 which I cannot wait for I am super fucking hyped I'm not even gonna like you guys now actually you guys probably would have saw that I didn't actually cover the first teaser trailer on my channel because I was actually out at that time and didn't really have a chance to do when I got back I saw everybody had already covered it and plus there's so much other shit to cover with the age of triumph I just really didn't bother because there's nothing new you could have learned from one of my videos well I don't think so anyway but the trailer is out later today and it's at 10 a.m pacific and for all of us UK folks it starts at 6 p.m UK time mark that shit down on your calendars write that shit down as a reminder on your phone because you do not want to miss this and if you do as always guys I will have you covered here on my channel now the speck of information I have for you guys today about destiny 2 is that Nolan North has been confirmed to be coming back and playing our little ghost now I know this is going to come as some bad news for some people as they want to dinkle back they want to peter dinklage back which to be honest wasn't ever going to happen the reason they actually got rid of him is because his time frame and shit he was too busy basically that little fella's too busy filming the Hollywood movies and fucking series like Game of Thrones and that and he means he didn't have enough time to do what bunch he needed him to do for ghosts and all the new voice lines that they would have needed with the rise of iron and the age of triumph and so forth Nolan North was a lot better suited for what they needed and that's where we got Nolan North and we have got him coming with destiny 2 and it was confirmed yesterday and I'll leave that clip linked in the video description where he said it on a show not sure what the show was but he did confirm that he was coming back and eyes up guardians is what he ends with so guys that's what you gotta do eyes up later today destiny 2 reveal trailer I cannot wait for like I said 10 a.m pacific 6 p.m GMT for all of us UK folks do not miss it but if you do like you said I will have you covered right here on my channel but guys if any more information drops about destiny 2 you guys know I will have you covered here on my channel so subscribe if you're new around here and like what you see click that bell notification next is that subscribe button so you never miss a video and I will catch you on that next one


The Republican Party gains control. The Republican Party, GOP, is now in power in the United States Congress and in the vast majority of state legislatures. Senate Minority Leader Mitch McConnell of Kentucky and House Speaker John Boehner of Ohio are the top Republicans in their respective chambers. The party takes a conservative stance on most issues, including opposing government health care, abortion rights, and same-sex marriage while favoring limited federal expenditure and low taxes. The Republican Party's current goal is to retake control of the Senate. To what extent do you think the Republican Party can regain control of the United States Senate? Would this work, and if so, how? What do you think? Let us know in the comments below.


So my name is Kevin Cluz, I'm from NVIDIA and my colleague Alexi Fomenko here from Intel. We're going to be giving a joint talk on device plugins 2.0, how to build a driver for dynamic resource allocation, otherwise known as DRA. So what exactly is dynamic resource allocation? Well, it's a new way of requesting access to resources available in Kubernetes 126 and beyond. It provides an alternative to the count-based interface of, for example, asking for NVIDIA.com slash GPU2. And using this alternative interface, it puts full control of the API to request resources in the hands of third-party developers. So if you have simple devices, you can continue to use the existing device plugin interface. But for more complex devices, this new mechanism exists to give you a much more powerful interface. One can think of dynamic resource allocation as sort of a generalization of the persistent volume API for all types of resources, not just volumes. And the key concepts that you want to have in mind when you're thinking about dynamic resource allocation is that of the resource class and its associated class parameters, which help you define the API for resource classes, as well as resource claims and resource claim templates and their associated claim parameters, which I'll go into a little bit more detail as we go through the talk. So before I talk about those, I want to just go through a really quick example and show you, you know, demonstrate kind of how you would move from a user's perspective of requesting access to a device via the traditional device plugin API and what that same request would look like under DRA. So in traditional device plugin, if you were to ask for a single GPU under your limit section of your resources spec in your pod spec, you could ask for something like NVIDIA.com slash GPU1 and you would get access to that GPU at runtime. Under dynamic resource allocation, a similar allocation would be done using what you see here on the right. So the things to note here are that I have this object, this separate object from my pod called a resource claim template. Inside that resource claim template, I give reference to a specific resource class. In this case, the resource class name is called GPU.NVIDIA.com and this is something that's associated with the driver that I'm going to talk through today, how you can develop one of these. But this name gets associated with your driver, is installed by the cluster admin and is kind of analogous to the resource type that you have from the device plugins of NVIDIA.com slash GPU on the left. Once you have this resource claim template in place, you can now in your pod spec, there's a new section called resource claims where you can refer back to the name of that resource claim template, create a local name for your various containers within your pod to reference that and then put that underneath a new claim section in your resources spec for your container. Once you've done that, the driver under the hood will kick in to allocate a GPU for your container and when your container comes up, you'll have access to that GPU. If you then expanded this to where on the existing device plugin API, you were to request two GPUs. On the right, that would basically be referring to this claim template multiple times, having different local names for the GPUs that you want to access and then plugging those into the actual claim section of your container to get access to the GPUs that are represented by that. With that kind of simple example in place, obviously it's much more of a boast than you have with the existing device plugin API. The obvious question is, why would I want to do things this way? I hope by the end of this talk, you'll be convinced that this dynamic resource allocation way of getting access to these types of resources is much more powerful. The first concept that I talked about is this notion of a resource class. A resource class basically associates a named resource with its corresponding resource drivers. If you remember from the last slide, the resource class that I defined was called GPU.NVIDIA.COM and the driver that I would install on my machine to be able to allocate resource classes of type GPU.NVIDIA.COM, in this case would have the name GPU.Resource.NVIDIA.COM. Along with these resource classes though, which is something different than what you can do with Persistent Volumes API, is you can associate an optional class parameters object which has a completely custom API that's up to you as the resource driver developer to define what this looks like. In the case of NVIDIA GPUs, this is actually a real class parameters object that we have for the driver that we built for GPUs. You can set up something like saying that any GPUs that are allocated by this resource class cannot be shared. If you want to make sure that you have exclusive access to the GPU versus multiple people referencing this resource type and you don't want them to share access to it, if the admin decides to install this class parameter object along with his resource class, it'll limit that sharing capability. Moving on to resource claims, this is the user side analogous thing to the resource class where the resource claim represents the actual resource allocation to be made by a resource driver as defined by the end user. They create these objects, they refer to the resource classes that they want to allocate resources for, and then when they're referenced inside the pod, these resources get injected into it at runtime. Where the main difference between a resource claim template and a resource claim is the resource claim templates create a new resource claim on the fly each time that they are referenced. From the example I had before, the end result of this in the case of GPUs is that you get a unique GPU for each reference store on these resource claim templates. On the flip side, if you have a resource claim that's not a template, it always refers to the exact same object anytime you refer to it, which basically enables you to have shared access to a GPU for each reference. Just as with resource classes, resource claims can include an optional set of claim parameters with whatever custom API you've decided to define for your resource type. For NVIDIA GPUs, one of the claim parameters objects that we've created is called GPU claim parameters, where the example that I'm showing here is basically letting you say, okay, whenever someone asks for, or when I create a claim that wants to access a GPU, in this example, I can say, okay, that GPU has to either be of the product family T4 or a V100 with less than or equal to 16 gigabytes of memory on it. So it lets you selectively dive in and more precisely ask for the type of GPU that you want to get access to. Additionally, you can specify extended parameters such as what sharing strategy you might want to enable for the resource once it's been granted to you. So NVIDIA GPUs have a couple of different sharing strategies you can use. One is time slicing, one is MPS, which allows you to further subdivide the memory that you have amongst different clients that are sharing access to the GPU. You can specify all of this as part of this custom claim parameters object that we've defined as part of our API for accessing GPUs with DRA. So assuming that you had one of these claims created with the name shared GPU, I can reference that in my pod spec and then multiple containers within that pod can reference that exact same claim and get shared access to that underlying GPU. And it's not limited to within a pod, you can do the same thing across pod. As long as you've created this resource claim as a global object, you reference it. Now different containers from different pods can access that same GPU. Now, one thing I don't have on the slides, but it's probably worth mentioning is that we do resource claims are isolated to a specific namespace, so you can't share these GPUs across different namespaces. Once a resource claim exists in one namespace, the pods that are running have to be in that same namespace in order to access the resource claims that are created as part of it, as a security measure. Okay, so kind of walking through those simple examples, the goal of this talk is really to teach you how to write your own DRA resource driver in order to enable similar features on your own custom resources, right? It's great that we've, you know, taken the initiative, built this initial driver for NVIDIA GPUs, but I really want to, you know, enable, you know, third-party developers for whatever devices that you guys might want to make available to be able to do something similar. Yeah, so with that, the outline of the rest of the talk is that I'm basically going to walk through the anatomy of what one of these DRA resource drivers looks like and how they work under the hood. I'm then going to walk through the process of what it takes to actually allocate a resource using DRA, what happens behind the scenes once you create a resource claim, and the resource that you're asking for finally gets injected into your container and you have access to it. And then I'm going to walk through the process of some helper libraries that we have to teach you how to build one of these resource drivers and what functions and methods you need to implement in order to make your resources available in a similar way. Then I'm going to hand it over to Alexa who's going to talk about some of the new and upcoming features that we're building in relation to DRA and end with a demo both on NVIDIA GPUs and Intel GPUs to show the flexibility of this across different resource types. Okay, so what does one of these DRA resource drivers look like? Well, at its core, it basically consists of two separate but coordinating components. You have a centralized controller that's running somewhere in your cluster with high availability, and then you have a node local cooblet plugin that's running as a demon set on the nodes that where the resources themselves actually need to be advertised and eventually prepared for use. The centralized controller, its job is basically to coordinate with the Kubernetes scheduler to decide which nodes an incoming resource claim can actually be serviced on. Once it's made that decision, it performs the actual resource claim allocation after the schedulers pick the node where that pod should actually land to get access to that resource. And then once everything's done, it will perform the deallocation of the resource claim once it gets deleted at some point in the future. On the other side, the node local cooblet plugin, its job is to basically advertise any node local state that the centralized controller will need in order to make any allocation decisions at runtime. Also, once those allocations have been made, it will then perform any node local operations that are required as part of preparing or unpreparating the resource claim. And we'll go through a couple of examples later on of what this might entail, rather than just device might not just be already ready to go. You might have to set up some parameters on it, depending on what the actual resource claim coming in looks like. And then once it's done that, its job is to pass the devices associated with that prepared resource claim to the cooblet so that it can eventually forward them on to the underlying container runtime and make those resources available to the running container. So I talked about these two pieces obviously need to be able to communicate in some manner. The centralized controller makes allocation decisions, cooblet plugin tells it what resources are available so that it can make those allocation decisions. And so there's a couple of different ways that this communication could happen. For the purposes of this talk, I'm focusing mostly on this first one, which is kind of a single all purpose per node CRD, which can exist in your cluster, where the cooblet plugin will advertise all available resources that it has. The centralized controller will track any resources that it's allocated in the same CRD. And then the cooblet plugin will also track any resources it prepares inside the CRD. So there's for one CRD you can get the full view of everything that's associated with this driver in terms of what's available, how things have been allocated, and what's actually been set up on the node for someone to get access to. Alternatively, you don't have to do it this way. You could have some sort of split purpose communication where the cooblet plugin might still advertise it's available resources for CRD via CRD so that the centralized controller has an easy way to access these. But then the centralized controller might actually track all its allocated resources down through this field that we have in the resource claim itself called a resource handle. It might not need to be something that's stored in the CRD accessible via the API server for making things a bit more efficient. And then at the cooblet level, instead of using a CRD where you might have constant conflicts when you're writing back and forth to it across these different components, instead you can just checkpoint the state in a file on the node local file system so long as the cooblet plugin has a way to track this over time. But like I said, we're going to focus at least for the purpose of this talk on the single all purpose one just because it's easier to talk about if it's all in one place. And what this might actually look like under the hood is that the cooblet plugin, when it first comes online, it'll advertise some set of allocatable devices that the controller at some point in the future could allocate. When the centralized controller is triggered to do an allocation, you could pick one of those devices, write some information back to the CRD about what GPU has been allocated to a specific claim. And then once the cooblet plugin kicks in and prepares this claim for use, it can also write this back to the CRD saying, okay, you allocated that and now I have prepared it for use before it gets passed off to the container that gets started later on. So what does this process actually look like? So how do we actually allocate a resource using one of these drivers? Well, there's two modes of operation for this. One is called immediate and one is called delayed or wait for first consumer where the main difference between them is that with immediate allocation, and this is something you can specify in your resource claim as you create it as an object in the cluster. And with immediate allocation, as soon as you create this resource claim, that's going to trigger your resource driver to allocate it on some nodes somewhere in the cluster independent of what pods might actually try and come along later to access it. And the pods that do reference that claim will end up being restricted to the nodes where those allocations have been made. So it's a bit more restrictive in the sense that you don't know where these pods, what are the resource constraints they might have. So doing an immediate allocation is really a means to say, I know that anytime at some pod reference that I want it to be on this specific node, whereas the delayed allocation delays the allocation of the resource claim until the first pod that references it is being scheduled. And there's analogous things in the persistent volumes API. So for those of you that are familiar with that, this might not seem too foreign. And when you do the delayed style allocation, resource availability will be considered as part of that overall pod scheduling decision for the first one that accesses it. And we're going to focus, because it's the more complicated one, we're going to focus on the delayed one for, as I walk through the process of allocating a resource using a DRA driver. So assuming that this admin has come along, he's deployed his DRA resource driver, got a centralized controller set up, demon sets running with the KubeLit plugins. He's also installed some resource class that, you know, enables someone to come along and create a resource claim that references a specific resource type that that driver knows how to service. The user can then come along, create one of these claims, create a pod that references that resource class, create a pod that then references one of those resource claims, which is then going to trigger the Kubernetes scheduler to actually see that pod and start the scheduling process, right? When it does that, it's going to generate a list of potential nodes where it thinks that, you know, where it knows that it could potentially put that pod independent of the resource driver, giving it any information at this point about, you know, where this resource itself can actually be allocated. And when it does that, it creates a new API server object called a pod scheduling context, which the centralized controller is able to pick up and see this list of generated potential nodes and help modify that and, you know, trim down to the point where an actual scheduling decision can be made. So once the centralized controller picks up this list of generated potential nodes, it will narrow down that list of nodes to the ones where it knows it can allocate the resource associated with this resource claim. It'll write that narrowed down list back to the pod scheduling context, who will then be picked up by the Kubernetes scheduler to help, you know, figure out which node we should actually allocate this schedule this pod on. And this process could end up completing repeating over and over again until the actual node has been found where this resource is able to be allocated. But once that is found, the Kubernetes scheduler will select a node, write that back to the pod scheduling context, which will be picked up by the centralized controller, who then goes through the process of actually allocating the claim, knowing that this is the node where that resource needs to be made available. It writes that allocation back to the resource claim object that then gets picked up by the Kubernetes scheduler, who does the pod scheduling, writes the node name back to the pod where that pod has been scheduled, which then through the normal processes that already exist will be picked up by the Kubelet, who then will call into the Kubelet plugin associated with your driver, passing all the claim information associated with that resource claim to it, who will then generate a list of what we call CDI devices, which it can then pass on to the container runtime, who will then start your container with access to the resources that your driver has allocated. So it's kind of, there's a lot of back and forth going on, but most of this is hidden from you. And we, as I mentioned, we have helper libraries that abstract a lot of this out, so you don't have to worry about all this coordination back and forth across all these components. Now, you know, I said we're going to focus on delayed allocation, but it's worth looking just really quickly at what immediate allocation would look like. So assuming you had a user that came along, created a resource claim referencing a resource class, as I mentioned before, the minute you create this claim, that's going to trigger the centralized controller to make this allocation on some node in the cluster, so that at some point in the future, when the user comes along, creates a pod, that's going to get picked up by the Kubernetes scheduler, now he's going to use the information about where that resource claim has been allocated to make his scheduling decision to trigger that whole process on the right again. Okay, so that in a nutshell, it's a long complicated process in many ways, but you know, the rest of this talk is now dedicated to knowing that that background information about how all of this happens. How do you actually build one of these resource drivers yourself, right? And so this slide here, if you take nothing else away from this talk, and you guys want to build a resource driver, this is the slide to remember, because we've created an example resource driver that we've, you know, put as a repo underneath the Kubernetes SIG organization on GitHub, that has an example of all of this. It provides a fully functional DRR resource driver on a set of mock GPUs. It wraps everything in a Helm chart, so you can easily deploy it. It provides scripts for bringing up a kind cluster to test all of this in a multi-node setup, and it runs on Mac and Linux without requiring any specialized hardware, right? So you can clone this repo, run a couple of scripts, see the demo running, and then dig into the details yourself to kind of tinker around with it and figure out how everything works. And the readme itself includes a demo with four example deployments that you can see here that are mostly revolved around how do you enable some of these sharing capabilities, given that you have resource claims at your disposal now. And yeah, like I said, I encourage you to fork this project and play around with it yourself. But in a nutshell, what it takes to actually build your own DRR resource driver is you want to decide on a name for your driver. In our case, in the example so far, I've been talking about, you know, gpu.invidia.com, but in your case, you would come up with some name for the driver for the resource type that you're trying to advertise. You would then need to decide on a communication strategy, whether you're going to use a single-purpose CRD like I've been showing up until now, or some combination of the split-purpose communication, which was presented earlier as well. Then you're going to need to define some types to represent your allocatable resources, your allocated resources, and your prepared resources so they can be tracked on these three different levels. You also then need to define some types to represent your class parameters you want for your resources and any claim parameters that you want to define the API for accessing your resources. You should prepare at least one default resource class for distribution with your resource driver. So in the case of GPUs, we have that one resource class called gpu.invidia.com that you then access through the claim parameters object, which can help you dig into to get a GPU type that you actually want. There's then boilerplate code you can pull into your project to register a controller with the scheduler. There's boilerplate code you can pull in to register your plug-in with the cooblet.  That's what I'm going to focus on today because this is where the particulars of your specific driver come in, where you're going to need to implement the logic for how you make your resources available. We provide a couple of helper libraries to make this a little bit easier. The first one is the controller helper library. Its job is to abstract this whole communication between the scheduler and this coordination back and forth to where you have to figure out what node you want your allocation to land on. That all happens behind the scenes. We provide a driver interface with five functions that you need to implement. As long as you implement these five functions, behind the scenes, the rest of the library code will make sure that all of that talking to the scheduler and making sure that you eventually do the allocation at the proper point in the life cycle of the claim is abstracted behind all of these function calls. I'm just going to walk through each of these one by one. The first set are the get class parameters and get claim parameters functions. These are the easy ones to implement in many ways. Once you've defined your class parameters and your claim parameter object types, the only thing that these functions do is basically give you an API into or a hook into a point where you can say, okay, I see that for the specific class or claim, there's a claim parameters reference specified inside it. This gives me the opportunity to pull that reference, the actual object associated with that reference down from the API server and then return it through this interface object that's the return type from these functions. What that basically does is it makes these objects now available in all of the other calls without you having to repull that from the API server every time. The second one is the unsuitable nodes function. This function is the one that kind of sits behind the scenes during this whole loop with the scheduler back and forth about deciding which node you actually want a pod to be scheduled on to satisfy the allocation that you're trying to make. What you basically do in the body of this function is that you need to loop through the potential nodes that you're past in search of available resources on those nodes and then write back this narrowed down list of nodes where the resources are unavailable into this claim allocation struct that gets passed to you. You can imagine that there's a whole bunch of nodes, there's a whole bunch of claims associated with the pod you're trying to launch and you just need to write that logic to figure out where these resources can actually be made available for that pod. The next call is allocate. This is the call that gets invoked as part of the process that you see on the bottom here with delayed on the left and immediate on the right. Once the scheduler is actually selected a node and the centralized controller is triggered to make an allocation, this is the function that you implement to define the logic for how that allocation actually happens. You end up writing that information back to the CRD if you're using the centralized CRD approach for communication. Associated with that is the return type here of an allocation result which has a field inside of it called a resource handle which is just some set of opaque data attached to the claim that can be passed back to the cooblet for arbitrary interpretation. You can think of this as basically just a long string that Kubernetes doesn't know anything about and it's just a way for your controller to communicate with your cooblet plugin and he can interpret this data however he wants. Then obviously the last one is the deallocate call. Once the claim itself gets deleted, deallocate will be triggered and you can clean up anything that you've done from your allocate call. That was all on the controller side. Now on the cooblet plugin side, there's basically two components that you need to be aware of. One is a helper library which lets you set up registration and actually get your cooblet plugin talking to the cooblet to begin with. Then there is the cooblet plugin API which defines two calls, node prepare resource and node unprepared resource. Under the hood, they're fairly straightforward. When you get a node prepare resource request call coming in, you have all of the information associated with the claim that you're supposed to prepare the resource for and you do that, you take that information and at the end of the day you need to pass back a set of CDI devices. I keep throwing this term around CDI devices without really defining it. It's a bit out of scope to talk through what CDI devices are but it's a CNCF sponsored project for standardizing on how devices can be made available to containers and we leverage that in this DRA project and it becomes the foundational piece for how you actually make these resources available at the end of the day and I encourage you to look up CDI container device interface to learn more about this but it also is built into this example driver that I have so if you just go into the code and look at it, it should be pretty self-explanatory how it works from there. Then on the last call unprepared resource request, you get a similar struct passed to you with the claim information that you can use to undo any preparation that you've made via the prepare call. With that I'm going to hand it over to Alexei who's going to talk about some of the new and upcoming features with the DRA resource drivers in general. Thanks Kevin. Hi all. What you have just heard was available since the last release 126 and in the release that we have received last week 127 we have a new improvement of the dynamic resource allocation. In particular, it is possible now to create a custom resource drivers and controllers to allocate several kinds of devices or maybe similar kinds of devices but at the same time. In this case the communications or bookkeeping what resources and how many resources were allocated already have to be done somehow publicly so that both of the controllers that allocate the resources can access this data. Consider that the native or original resource driver allocates part of the resources then the custom resource controller has to know about that decision and other way around if the custom controller that is supplement supplement in the original resource driver controller makes the decision and allocates a bunch of hardware then the original controller has to know about that decision so that there is no overbooking or a false decision. And there are at least two use case for these scenarios one is when you have different kinds of hardware that somehow have to be for example aligned with the locality the normal locality or other way then the controller can consider these resources of different time for example a network interface and the GP adapter and make a decision that these are the hardware that have to be allocated and this information will be later on passed to different cubilette plugins. Another use case scenario is when you have a similar kind of devices and if the workload doesn't care what kind of or what vendor of the hardware it gets it's a vendor agnostic it can deal with any kind of hardware then there can be a custom controller that can manage all of the vendors devices in the cluster in this way. So in this case the allocation would have begun with the different resource class so naturally since we have a custom resource driver then we have a resource class that guides that the resource claim should be forwarded to this new controller custom controller for the allocation and when doing the allocation the custom resource driver controller will make several resource handle entries in the allocation result that is written to the resource claim and each of these resource handle resource handle entries will contain a driver name that will be used by the cubilette to ask the cubilette plugin to prepare the actual device when the pod is going to the node. Now another feature that will be coming hopefully in 128 is allowing several resource claims that will be used by the same pod and are targeted to the same resource driver all of them will be able to be allocated at the same time so at the moment the unsuitable nodes call the one that narrows down the amount of nodes the main scheduler can use to pick up where on which node the pod should be scheduled on this call receives all of the resource claims of particular resource driver at once so the resource driver that you are building can consider the whole amount of the resources that will be used by the pod but when the allocate call comes to the resource driver the resource claims are passed at the moment one by one so that's a different kind of consideration of resources by the resource driver and that can bring you to small problems but nasty problems for example if you have two pods that were deployed simultaneously and they have multiple resource claims unsuitable nodes will report to the main scheduler that the node A is suitable for both of these pods but when the actual allocate call sequence will start for every single resource claim at some point there might be a resource depletion and the scheduling will have to start all over again so the natural solution for this is to make the allocate call to look the same as the unsuitable nodes call so we plan into pass the whole bunch of resource claims for particular pod so that the allocation call will have a chance to see the whole amount of resources that need to be allocated for a particular pod and the same problem applies for the cubelet plugin especially if the hardware is capable of only handling one entry of the configuration then for example virtual functions on some of the SRIV capable hardware once several virtual functions were provisioned then the subsequent vfs can only be provisioned when the previously created ones are dismantled so if your pod has requested two standalone virtual functions then the unsuitable node call will report that okay this GPU on this node seems to be suitable and then allocation and preparation will actually face the situation that the first one has a chance to be created in the SRIV capable device but the other one cannot anymore be created because of the hardware limitations so similar way if we pass all of the resource claims at the same time to not prepare resource and not unprepared source then it's much easier to book keep and handle the resources by the resource driver so this is what it is now and this is how we think it will gonna be in 128 this is work ongoing thank you I think we have three minutes for questions yeah so the sorry the question was is the centralized controller a scheduler plugin no it's not it's its own it's its own entity I mean you could think of it as a scheduler plugin but it's not part of the scheduler plugin framework that exists in Kubernetes it exists as part of the DRA framework that knows how to communicate with the scheduler via this pod scheduling context object that that I talked about in the slides earlier there there is a scheduler plugin but it's associated with the DRA framework in general it's not something that you as the resource driver developer need to worry about implementing anything for yeah yeah and we had a couple of demos that we can show people that are interested after this talk but we we ran out of time so we're not going to be able to show them but if you're interested please come talk to us after this and we can go through those with you are there any other questions yeah um so if uh if I have like AI ASIC chips uh is it possible to do topology aware scheduling for example now with the DRA support or something we are looking at uh in the future yeah so um currently we haven't thought in detail about you know exactly how we're going to enable the whole topology aware or you know solve the topology aware problem um our kind of default answer at the moment is that if you want to do some sort of alignment you build a custom controller that knows how to do the alignment for all the different resources that you know you need to be aligned right and because we have this level of indirection where you can have you know the default drivers for all of your types and then you just write your custom controller without having to rewrite the kubelet plugin logic it enables you to do this for your custom environments where you know exactly which resources you want to align and can just write that allocation logic rather than all of the prepare and unprepared logic as well okay thank you in addition there is another technology just was just released called node resource interface that can help you align uh what you want but it's outside of the DRA framework and it's uh outside of the resource driver so it's something that resource driver can leverage but that's another couple of API calls and strictly speaking it's a best effort so if you're interested in this the main author and maintainer of DRA framework Patrick is going to be at Intel booth p13 and we have also people there who involved with the node resource management and the nri come talk to us one question do you have some recipe how how this can be it can work together with some legacy device plugins what do you mean by work or what do you mean by work together so at least our plan for NVIDIA GPUs with our device plugin is that we're going to allow you to on a node by node basis decide whether you want to deploy the existing device plugin or the DRA kubelet plugin basically um so you know there won't be a mix and match for being able to allocate but via both methods on on each node but at least throughout your cluster you can have some DRA enabled nodes some nodes that are enabled by the existing device plugin so that end users can slowly migrate their applications to using the the DRA style of asking for resources yeah and there's technical reasons why we can't really do them together on the same node mostly because the device the device manager within the kubelet it's the one that does device allocation by the device manager or the the the existing device plugin framework the the plugins themselves don't do allocation they just do advertisement of resources and so we can't coordinate that allocation between our resource driver and DRA and the existing device plugin allocation because we'd have to basically change the kubelet to do that but otherwise it's not exclusive it's not like if you're using a DRA dynamic resource allocation the rest of the devices of different kind cannot be used in the cluster they can live inside the same cluster and some of the hardware can be managed by the device plugins and some of them can be as long as they don't conflict so we need to patch our kubelet at least 128 to use dynamic resource allocation with NVIDIA GPUs or can we use it before with the new mechanism yeah I mean officially you shouldn't be using it until DRA reaches beta which is going to be at least another couple of releases but if you want to start prototyping and using it now 127 is enough so you can you know use 127 there's some feature flags that you'll need to enable when you start up your 127 cluster because DRA isn't on by default as an alpha feature but then you should be able to follow the instructions on our NVIDIA DRA resource driver for GPUs link that's here in order to start playing around with it thank you I think this will this will be the last question can this be used in conjunction with the CNI to for example allocate a vf to a pod from a dpu yeah so we have a separate project going on inside NVIDIA for doing exactly what you just said so it's a separate resource driver to our GPU resource driver but it's allocating vfs for our DMA on DPUs thank you yep thank you everyone


Do you see? Yeah. Okay. Sorry about that. Can everyone read that? Yes? Yes. If Paul can, I think everybody. Yeah, we should. Another line. Yeah. Yeah. Where is that? I don't know. I don't know. Take it, sir. Take it, sir. Take it, sir. Take it, sir. Take it, sir. Take it, sir. Take it, sir. So, I'm going to talk about algebraic data types, and it's going to be an introduction for very early beginners. Yeah. So, this is the first talk in a series of talks that we're going to try called 101s. So, this is the ADT 101. It's also an experiment because I'm going to do it with the working Askel module and Dock test. So, this is a DIMM session, and I am able to run, to actually load the file in an Askel compiler and then run the Dock tests. You can see here the Hello World. This is how Dock tests work. So, this is what you could enter in an Askel REPL. And then it checks that the output that it gets from an Askel REPL actually looks like that. Here you can see that the exclamation mark is missing. Can you see that on the right? Yeah. Yeah. So, I forgot the exclamation mark. If I had that in, I would actually see that this works. Yeah. So, but this is a bit of an experiment to see whether it works to give a talk with a module like this. I hope that the talk is going to be more interactive for that. So, yeah. If you have any questions, I want to try out something I can edit the code and then we can see what the compiler says and what that works on. So, feel free to intercept. So, algebraic data types are very fundamental in Askel. They are much more fundamental than lots of other stuff that people talk about, like type classes or type test instances. They are much more fundamental than monodes, for example, functions, monosransformers, or other related concepts, a category, if you will. Yeah. I'm going to stop. So, they are definitely not more fundamental than polymorphism. You can't claim that in this trade. I mean, polymorphism comes into play even if you don't have ADPs at all. Yeah. In the minor class system, without ADPs, at least five different students. Well, as I have a BIM session, I can delete that. I prefer that. Because it's a beginner's talk, right? I mean, that's not a discussion to have in a one-on-one talk, I guess. Yeah, fine. But I think it's important to emphasize that ADPs are very fundamental because it's very easy to get confused by the typical learning materials in Askel that usually center on monodes. And monodes are not the thing that you should learn first. The first thing you should learn first is ADPs and maybe polymorphism and higher order functions and some of them. But yeah, I'm going to talk about ADPs. The target audience, as I said, are absolute beginners. I do have the ambition that some intermediate Haskellers will gain some intuition for data types. But I'm not sure that I succeed. Let's see. So the first concept that I want to talk about are so-called product types. Here you can see a very simple declaration of a product type that encodes a two-dimensional position. And what happens here is that you declare two things. One thing is a type that is called position, which is indicated by the word after data. And the second thing is a constructor, which is also called position. It's not a problem that they have the same. They don't have two, but it's not a problem that they have. And it's common that they do. And a product type is a Cartesian product of its fields. So this product type has two fields, both int, one is the x component and the other one is the y component. And with that, you can construct values of the type position using the constructor position. And you just stick two values in there that are both of type int. And then you get a value of type position. You can see that here. So this then you can say, well, I want to have a position where the first field is three and the second field is five. And then you get that. You can also do a bit more complicated stuff. You can say that the x component is some calculation. And then this will actually value it to this. It doesn't make sense so far. I think Victoria is not her inner ear. She is younger. Maybe we'll have to take a minute. Does it make sense? Yes. Alisa? So I think the term constructor is also used in OOP, for example. And Haskell works quite differently. And Haskell constructor is really something that doesn't do anything. You just stick values in it and then it contains these values. Sometimes I also think of a constructor as a name tuple. It's just a tuple of two numbers. And it has this type position. But it cannot do anything else. Is it just structured and like C? Yes, it's like a structure. Yes, exactly. Yeah, it's atomic. You cannot split it up anymore, right? Constructor is just like, cannot be looked at, kind of inspected further. And one interesting thing is that if you have a value of type position, it has to be constructed with the position constructor. There's no other way to construct a value of type position. At some points, it's going to be a position constructor. Of course, we can have a function like this one, make position. It takes an int and then just creates a position for you, which in this case, well, for example, if you give it a four, it will just set both components to four. But somewhere at the lowest layer, it is going to use the position constructor. One thing that I haven't... It's something that people don't talk about that often, I guess, but that I found very useful is something called implicit signatures, which is... So if you define a data type like position, you do get implicit things. And of course, talking about the constructor. And these implicit things do have types. And it's... For example, in our example, this is how you ask the Haskell compiler for a type of something. So here I'm asking, what is the type of the constructor position? And then it tells me position is a function that takes two ints and produces a position. Right, like if we look at the position data type, it's not completely apparent that that's what we get, but it makes a lot of sense when you think about the constructor as something that you stick the values in and then you get the value, right? So I think it's often useful, especially when we start thinking about these things, to bring these implicit types to your mind. That means that you will present partially applied constructives. You will show partially applied constructives. No, I won't show anything partially applied. Another thing that you can do, which is slightly... Gives you a bit more power for product types are selectors. So you can define... This is a very similar type, right? But you can, at the type declaration, also give the fields names. So this says the first field is called pause x and the second field is called pause y. And that gives you actually a function, pause y, two functions, but one is pause y, that actually does what we expect you to do and extracts the one field. It's like key for a passion. But when you extract the value by key, a map or a passion or something, so it's extractable. Yeah, a bit... It's very rude, for example. But it's a field of a structure, because it's typed. Yeah, I think it's more similar to... You showed a type of possible? Right, another. Yes, again, pause one and pause x do get implicit signatures. So what you do get is a function, pause x, that has the type position two to eight, right? And then there's no special syntax for accessing that field. You just get this function. But it's more similar to like a dot accessing of structs or something. Still think it's in so far a good comparison as that commonly it has the programs. You see rarely the use of HashMap or DreamMap, and in other languages we see them a lot. And basically we replace them by these records. It's useful, especially as it has to be. Most of the time you think you want to have HashMap, you don't want HashMap, you want this one. Because it is typed. Yes, I mean, the only reason you will ever take HashMap is if you don't know your domain, then it's a keyword, so your domain is open. Yeah, okay, and what is a keyword? Yeah, yeah. There's no... There's no, like, any keyword type of thing. Yeah, you can put new keys in there.  Yeah, yeah.  No, but in a comparison setting, right, if you have a non-unit type language, then it makes perfect sense to have fields, typed fields, right, which are static, which is very different from a runtime domain for some associative data structure. It's very like a language-specific, right, because for some languages, you may have type variables, for some, you may not have, like, for example, for Ruby, you may have, like, type variables, just like this thing with, like, value variables. Right, no, no, no, no. I mean, it's like, unless your language is unit type, like Ruby. Ruby doesn't really make much of a difference because we don't have types, static types, anyway. So this whole distinction, but in, like, C++, which is, or C, even, right, which is imperative, but it still makes sense to have a struct with a static set of fields with static types. But even in C, that doesn't mean that you don't need associative data structures like a NashMap, right, because it's completely different thing for some kind of problem where, you know, you process something, find out what the keys are, then you're going to need a NashMap, even though, or not a NashMap, but some associated data structure, even though in C you have records with static fields. So this is more like the C record fields. Because it doesn't mean, talking about the C struct field names, you're implicitly littering your namespace with all the fields. That's like a word of Haskell. It's really bad. So yeah, what you actually do get is this function for y and for x, these two functions into your scope. So you couldn't have another type with the same few names for you now? Yeah, I would have loved to name these x and y, but I use x and y somewhere else. On the other hand... On the one hand you fire, what's this? Please ignore that for now. That's all. That has little to do with algebraic fatal times. Oh, yeah. But yeah, does that make sense? Any other questions? So, so far what we have done is only construct values, right? What we want to do with positions, what we also want to be able to do is deconstruct values because we want to do something with that. And here's a small example that figures out whether a position is valid. I'm talking about chess, by the way, if anyone is wondering what the domain of this is. Why are positions with integers and not doubles? Yeah. So what you can see here is that the position of type position to bool and the deconstruction happens here. It's called pattern matching. So what happens here is that we say, well, our input argument is of type position and then we can use the constructor to actually deconstruct the position value and get the x and the y. So what will happen is that the actual two fields will be bound to x and y. So these are arguments, parameters to the function now. Does that make sense? Yeah. Yeah. And it's valid. It behaves as we expected it to behave. Those are product types. And now the other fundamental concept with ADTs are sum types. And I have a very simple sum type here which is for color. Again, this is about chess. So what we have here are two distinct constructors that are alternatives. So the type of this is color. We declare a new type that's called color and it has two constructors, white and black.  And if I write down black, I get the black value of type color. Again, we have some implicit signatures that are much simpler now. So white, yeah, I just said that. White is a type of color and so on. Again, interesting is that in some types, if you have a value of a certain type, you know that one of the constructors is being used to construct that value. So if you have a value of type color, you know it's either white or black no matter how it was constructed. And deconstruction of sum types works like this. So for example, here's a very simple function that just figures out whether color is black or not. And here there's a case statement where you say if my given color and then you get any pattern mesh on the two constructors. If it's black, then return truth. And if it's white, then you evaluate default. Yeah. No test case for black. Does that make sense? No. And these are the two concepts that you use in Haskell to construct all your data types that you have. So every data type is a list of constructors and every constructor has a list of fields. Right? So for example, here I have a data type for a chess piece and it can either be a pawn and a pawn has two fields of position and a color. Or it can be a rook and that again also has a position and a color. So every data type is a sum of products, if you want. But then you can declare as many data types as you want and then you can stick them together so that that's actually how you can build quite complex structures. So for example, I have declared position myself and position is a two-dimensional position of things and I have declared color myself and that can be black and white and then I can use those to declare a piece which then is quite a rich data structure and quite nicely models what a chess piece is. I included Queen here just to show that these don't have to have the same number of fields at all. Like that's not a restriction. If you wanted to then you can do that but you don't have to. If there are any other chess players here then you can use the logic to choose. And again we have implicit signatures and I think it's useful to look at them. So for example the pawn constructor has the type position to color piece.  The information that it's pawn and not a knight is encoded in the constructor. Rook has the same type and Queen has a different type and it gets this Queen originally. It has this additional field. Yes. We can of course then construct use these constructors to construct something here. I construct Rook and what what. That's actually the correct position. So given that you've got this literary problem you now use the words original and created which are kind of useful words. Which I can't use for what? Yes. So you've implicitly created posex about what happens if you say is original or posex. What kind of error do you get? Well if... Let's try to reduce it. So... For example if... Creative was a posex. Well I mean this is not useful at all but if I did this then I would get this error message. Multiple declarations of position. Of course it sees that as reading. Well that doesn't work in Haskell, right? Like a Haskell declaration is a declaration and it's valid for all eternity and that's why this won't compile because it says like well you have two declarations for positions so which one should I take?  So yeah I mean this is a practical problem. You can put it in different modules and then you know figure it out through qualified names but yeah this is actually a problem to practice sometimes. Yeah this is an example of the deconstruction of this more complicated type called peace where we first have a case statement on the peace so the idea is that this function returns all the loud positions assuming that there's nothing standing in the way. So what we do first here in the first case statement is that we pattern match on the peace and we say like well if this is a pawn and then you can then recursively pattern match on the fields also right? The first field is a position and you can pattern match on that as well and directly get the x and the y in this case we also need the color because white pawns can move differently than black pawns and then we do a second pattern match on the color and we say well if it's white then we allow this movement and if it's black then we allow this movement. Again this is not about chess. Yeah but what I find interesting is that if you look at this piece of code then almost everything you do is concerned with deconstructing and constructing data structures right? It's almost nothing else. And that's actually what Haskell is ideally about that you design your data types so nicely that coding becomes very like everything falls into place just because you have to construct something of that type. Unambiguous. On line 192 is that the error case? Is that the error on line 188 and it returns you a type position error there or a string? That's very can you repeat the question? Oh the error case it returns this NYI string but you're returning in your function signature a type position. Yeah this is actually lazy I didn't want to program it all out so this is where you throw an exception. Yeah But that works even though it doesn't match your function signature?  So if you throw an exception you can do it anywhere and it cannot have any type. Yeah so that's just exiting basically. Yeah and then if you run into this it will just basically tell you like something wrong happened in NYI. Can you show the type of error? So that's why it matches. So what that means is that for any choice of a fantasy character? Yeah But what's the word for it then? Yeah I do want to give one on but you don't want to argue that error is more important than data types right?  But what is interesting about the error case is that I had to add it to get rid of this error message I did this warning so now I deleted the error case and then because you have these types with these constructors the compiler actually has a lot of information about the structure of your values and then it can tell you well you didn't tell me what to do in case of a rook and a knight and a queen you did tell me what to do in case of a pawn but before you declare that this can be different stuff and then I didn't want this warning and then I added this case so if you did this right for the other three types you would need the error case So do you always have to put in cases by every case even match every case You don't have to right this is a warning But of course you should take that warning seriously because it tells you that the type checker can't guarantee that you won't get a value of that with that constructor right So what happens if there's no error and you call for it with a rook It also throws an exception that is more general that says like oh there's an un-matched pattern and I don't know what to do Actually more useful than this many cases Yeah more useful than the NYI I really just added that to get rid of the warning I mean we can try that out right we can just go for the pawn which kind of works but we can of course put the rook here and then it will give us this exception Now we remove the error right Yeah so this now is not a compile oh no sorry the first one is the compile time warning and then down here we see exception and it's cut off and there you can see it So it gives you actually a source location and the columns of the lines and non-exhaustive pattern case which of course is much more useful than NYI Yeah that's already the things that I really wanted to talk about There are lots of random thoughts that I have here that we still have time we can go through some of them but so far Thanks for this Anybody is interested in listening more about SUPS So it's quarter past nine I don't know Anybody is half pressed to leave We have Thanks Thanks We're now hiring Haskell programmers Yes Syntax and laying out Haskell code Do you usually do function signature and then the implementation of the function of one to the other? Usually you do, you don't have to but that looks right Would it be an error if you did the implementation say at one, nine, one, eight would that be an error or can you There's a weird syntax I think it's a bit weird where you say where you say actually something like this For example what you could do is say this and then you have the next case here which looks like two definitions but it's not It's one definition of a lot of books It's just a weird way It's a function overloading function overloading of different No, it's not overloading It's the same function That's why it's so confusing That's why I wrote it down with case because then you can see it's one function This is just two lines This actually is semantically equivalent to the case statement where you have one declaration and then a case statement Because in this case if you call a lot of rules it would be line 192 but if you had a point it would fall in one, eight and if you had a queen it would still hold in one, two, eight Yeah, it would behave exactly the same No, it wouldn't fall into one It would fall in one, two Oh It would fall through and then we could You get the same thought as you get with a case So if it was queen you would fall in If you pass it a queen then none of the patterns will match and then it will throw an exception telling you like in the same syntax do these un-match equations Yes Yes, you can And what maybe gives some more intuition for this like if you do this for example then this is not allowed because then it would complain about multiple declarations of allowed moves This is the same like if you if you have it like this this is the same function it's not overloaded or anything Does it make some kind of sugar making problem? Yes, you could very well argue that this is syntactic sugar for a case I think the reason why we have that is that it just allows you to define functions like in a math book or if you write a paper then you may want to write it like that but for practical Haskell, people use that but it's not essential and I think it could be easily if it's only about practical program could be easily from my perspective and made it from language So standard practice using a case instead of multiple People use that syntax but I don't because if I reflect the things the case is easier to deal with People depending sometimes it looks nicer when it's the case and then you may also use eliminate the nested case here because you can put the white in the first equation and the second equation repeats the same but with black in place of color Yeah, you could you could do this, right and then you needed another case where you say black Doesn't make sense that this is the same thing It's because there is a lot of pattern matching or cases matching in Haskell So people do shortcuts to make it nicer Any other questions? I imagine this is a terrible one case You don't have to write keys You can just match this Yes, exactly We have seen a further upright If you have a function like this you wouldn't want to write is valid p equals case p of position x, y, arrow and then you just have one right hand side And I guess Simon also uses that Yeah, of course, in this case No, don't do it It's partially defined functions If you look at a more complicated example further down the problem is if you change anything and you don't have a case statement you may end up changing it on multiple lines If you add a function argument for example, you need to add it four times If you have the case statement you just add it on one time If this is for beginners I would like to stress that you should strive for total function every time If you have a sum type and you write a function over it then you should be able to provide a right hand side for every possible left hand side of your sum type If you have a function where you have one of the possible patterns is something that you don't need to write the right hand side you should regard that very strongly as a code smell that maybe the type you're using is not the right one maybe you're not modeling some of your assumptions on the type level because yeah, because the hassle is not a total language in itself you can write partial function but it's only going to cause problems further down because you will end up using that function somewhere deep down in some other code and you have no idea if the thing you pass to it is going to be one of the things that is not handle by your partial function in some sense this is all this is what static piping is all about if you have the right type then this is the class of problems that you should be able to avoid completely yeah yeah exactly so some of the random thoughts there one of them was that I think when you design a data type for a domain and then you code something with that then you do have to try around a bit to get it right there's often like a first first draft and then one thing that can happen is that you run into a function where you write something and then you realize you don't know what to do with one of the cases and that's exactly what we were talking about and then the compiler errors the warnings really help you and then you rethink can I change the design of my type such that I can get rid of this case for this one function and then you have to switch it around a bit so the goal is that when you design a type or a bunch of types that they model the domain that you have as closely as possible I mean of course you have to allow to encode everything that you need to encode but you should try to disallow as much embedded things that that should happen so an overly simplistic example would be that don't use an in if you're modeling a chess board because you know it's only going to have one of eight possible values right the inside is much larger than just one, two, three four, five, six, seven and eight yes yeah what I also I mean maybe it's not really ascal or specific but what I also really find important is that you shouldn't model anything that you don't need right I mean we've talked mostly about data types and we have done that much with them so that's why we do have a lot of things that we don't really use but that happens in practice too right like that someone tells you to write a chess program and then you say yeah that's good and we have pawns and ropes and board and pieces and then in the end what they want you to do is for example output chess quotes every day right and then you realize well that's we don't need any of the data model that builds so sometimes it feels weird what you can leave out right so for example I would guess that in this data type we could leave out the color of the rook if all we want to do is compute the allowed movements and you don't need to know whether that's black or white yeah you do do you want to catch her? the allowed movements is just like imagine that one rook on a chess board so it's a very friendly chess board it's a very friendly chess board well I mean that's what the allowed move functions like it doesn't even get to take the board into account it just computes the position that you can go to and for that we don't need the color we do need the color for the pawn because that can move in different directions but so what I usually do when I start designing such a data type is what I would actually do is start with something like this which defines a data type that doesn't have any constructors it's called an uninhabited type it doesn't have any values you can construct a value of that but I'm thinking like well as long as I don't know what I want to do with that and what information I want to put in there I just don't put any constructor in there and then at some point I need something to put in there and then I say well maybe this doesn't contain any information right it's just like there's only one value that this type can ever take which is peace but as long as I don't do anything with it I don't put anything inside just to avoid the risk that I put something inside that I end up not using because I wrote it down here Unused constructors and unused fields are dead code too like we usually think of dead code of things that does code that does something but a field that we don't use is equally harmful I wonder if there are some data models that you possibly sometimes you don't want to swipe your time model in the data domain so in Haskell maybe there is for example like commerce, aerospace or different data models already created in Haskell that you could reuse it seemingly well there are lots of libraries that define data types right for certain domains but usually they are quite generic well not always but so for example you could have a library that helps you interact with the Amazon API and then you would have all kinds of data types that allow you to specify the information that you want to send to Amazon and then you get another data type back another value of a certain data type back and then a library would provide these data types that model the inputs and outputs of this to go to the library there is no special repository with only data models that people maintain or standardize only in Haskell yes only in Haskell I also don't know if most could translate data types to any other system of ontologies that would somehow match exactly what Haskell data types can do maybe but I don't know so usually a library is like a mix of functions constants and data types for your domain because the operations that you want to perform on these data types also limit the domain that you want to accept well in those so in Haskell constructors are not really expressive enough to be useful enough on their own right if all you have there is an ADT without functions over it that's not providing much it's not like it's not like you have a rich language about what it means something to be faster it's only business dictionary which you could use not spend the time to model it but yes you don't know what to do with it either you have some functionality mind in which case you will have the function next to the ADT or if you don't but it's not providing much value to have just the ADT because like I said the language of constructor is not rich enough to encode anything non-trivial I mean if you look at it from the curry hour it ends but I mean we have a library that types HTTP HTTP types we have a library that finds types or HTTP mostly only types I mean there are some tools that actually look at some for example Miha wrote a tool that looks at JSON and then generates Haskell code that is data types for whatever however the JSON looks like but then as you said you can use something with that just the pure data type definition is useful but not a pro and in practice that is a very uncommon case like most of the times we were right there the data types by hand so like in Java in other environments you have some data models for pet industry they are standardized and so on sometimes it is useful but you need to have some default logic as you said I was only interested if you have something in Haskell so yeah, thanks I mean of course we do have something like libraries like data structures and that type but again together with the operations in Java if you get a clause then you are getting type definition and some method so in Haskell that would be getting some type definition plus functions but in Java you don't need to have the methods you want some abstraction to talk to the business user analyst and so on so you don't want to waste the time to analyze the business domain because some business don't make a long e-commerce banking they are quite standardized good question notion of extension of existing some type with more cases not in the simple algebraic data types for this you need to to capture the demand that seems to be here at some point his name is Lawrence and he has been working on data types a la carte in constructing data types together all making sure that your functions work for this data type and the other data types that are kind of derived from it but if he's not here I will not repeat his lecture because it's quite immediate quite long the technical terms closed the data types are closed you cannot after the fact add anything even if you have to also as the new alternative every function maybe a new type same some cases but maybe more cases but if it's a new type then you can easily create a new type or one of the alternative some product types where the first alternative just embels this existing type the second one is your first new constructor the third one is your second new constructor that's true I also wrote down something combinatorics like when you have this sum of products you can think about what is possible with this system so what you could have is a wrapper type that is just one constructor and one field it cannot possibly have more information than the type that the field has but it's a different type so the compiler can tell the difference then of course you could add another constructor to say sometimes I don't have the spell you have something else but then you cannot use the same selectors you have to always unwrap what you have wrapped that's usually intentional because if you wrap something you can mean that maybe it has some special meaning to not just every process ID just process ID that I produced in my program for example or not just every sockets just HTTP sockets so the information underneath is the same but the way you use it is different maybe you could also talk about the type for the wrapper I don't think it's such an important concept like this so these wrapper types what I'm thinking of is something like this or maybe we use something like minute what this tells you is there are not more minute values than there are int values but it has the compiler and the programmer that this is a minute and not something and then you can always use new type which changes I think rather are irrelevant things so basically new type means that it has to be a wrapper type yeah it is strict and you know where but so you can use a new type whenever you have one constructor and one field and then it's slightly faster and it's strict what I also find interesting are enumeration types so what you could do is you have certain flags for something and then you can have you know what I think Java they have enumeration types and in C you would then use enum and then you can just simulate that by some type where every constructor has no fields right and then one thing that might be interesting is why is it named some types and product types so the names come from I mean the product type of course there's the Trancartesian product but what I'm always thinking is that if you think about how many possible values a type has than in a product type for example if you have a product type of color yeah like this well then let's start with color right so this is some type and every constructor has only one value right like white can be one value and black can be one value and the number of possible values for color is the sum of these things right there's two possible values if we had another constructor then we would have to add that right and if we have a product type that takes two colors then the number of possible values of that constructor is actually the product of the possible values of our fields so this case would be four does that make sense I think if there are no further questions so again I encourage people


Hello Columbia and welcome to This Week in the City. Highlights brought to you from the public relations, media and marketing department with the City of Columbia. I am your host, Alicia Utsi. Hello Columbia. As we start this week in the city, we want to make sure that you know that Columbia Animal Services has now changed their hours of operation. Columbia Animal Services is changing their hours of operation. The new hours went into effect on July 5th, 2022. On Mondays and Tuesdays, they will be open from 12 p.m. until 5 p.m. On Wednesday, 12 p.m. to 5 p.m. On Thursday, 12 p.m. to 5 p.m. Friday, 12 p.m. to 5 p.m. And on Saturday, 9 a.m. until 4 p.m. And on Sundays, they will be closed. Again, Monday through Friday, hours will be 12 p.m. until 5 p.m. And on Saturdays, 9 a.m. until 4 p.m. And they'll be closed on Sundays. If you have questions, please call Columbia Animal Services at<PHONE_NUMBER>. They are located at 127 Humane Lane. Columbia Animal Services is also offering free pet adoptions. Columbia Animal Services is presenting PICME SC, a free pet adoptions program. The program started on Friday, July 8th and will run through Saturday, July 16th. Free pet adoptions on all animals at our animal shelter. The Animal Services shelter is located at 127 Humane Lane. You may call them at<PHONE_NUMBER> or visit our website at columbiasc.gov for more information. On July 12th, join the Columbia Police Department for a front porch roll call to be held in the Belmont community at 901 Colleton Street at the Leasing Office. Come on on July 12th and meet police officers who are working in your community. You can join them starting at 5 p.m. until 5.45 p.m. Also on July 12th, the Affordable Housing Task Force Committing Meeting will be held at 11 a.m. Please visit our website at columbiasc.gov for agenda items or to view the live stream of the meeting. Two COVID-19 vaccination and testing clinics will be held this week. The first clinic date and time will be July 12th. The location is Hampton Park, located at 1117 Brandon Avenue. The clinic will be open from 1 p.m. until 5 p.m. The second date this week is July 14th. Again, the location is Hampton Park, 1117 Brandon Avenue, and the time is the same from 1 p.m. until 5 p.m. You may come out and receive a free COVID-19 vaccination or test at Hampton Park on July 12th or 14th from 1 p.m. until 5 p.m. Are you ready for our next block party, which is a summer series? The Be Safe Block Party will be held on July 14th in partnership with the Columbia Police Department, Server Connect, Parks and Recreation, along with other departments with the City of Columbia. Join Server Connect, the Columbia Police Department, and Parks and Recreation on July 14th from 4 p.m. until 6 p.m. at Pinehurst Park, located at 2300 Pinehurst Road. This block party is open to the community, but it is also an opportunity to receive free gun locks from the Columbia Police Department. Lock it up, Columbia will be on-site at the block party to give out free gun locks to those in the community who would like to receive one. Also on July 14th, the Planning Commission will meet at 4 p.m. at City Hall and Council chambers. This meeting will be a hybrid, which means that you can actually attend in person, or you can watch the live stream from the city's website at Columbia SC.gov or from our YouTube channel. Also for agenda items, please visit the website at Columbia SC.gov. And on Friday, July 15th, it is time for Food Truck Fridays. Food Truck Fridays will be held on Friday, July 15th from 11 a.m. until 3 p.m. There will be one location for all food trucks, 2300 Bull Street, which is the REI Co-op parking lot at the corner of Bull Street and Colonial. There will be four food truck vendors located at 2300 Bull Street, T&A Southern, the Arepa Chef, Bessie's Bites, and Carolina Cookin. Come out and taste the delicious food from one of the food truck vendors again on Friday, July 15th from 11 a.m. until 3 p.m. located at the corner of Bull and Colonial at 2300 Bull Street. And as we close our program, we want to make sure that you receive your weekly reminder about youth activities and services for youth this summer. Columbia Parks and Recreation is sponsoring summer camps at three locations, Martin Luther King Park, Greenview Park, and Woodland Park. Also on Friday evenings, there are primetime events which are parties for teenagers 13 through 18 located at various parks throughout the city on Friday evenings from 8 p.m. until 11 p.m. You can find details on our website at columnsc.gov and also on social media platforms Facebook, Twitter, and Instagram. Make sure you stay in tune with what's happening this summer for youth in our community. If you're looking for additional activities, don't forget to either pick up a copy of our Youth Services Guide or you may visit our website at columnsc.gov for a link to the full guide and directory of youth activities this summer for children in the city of Columbia. Thank you for watching this week in the city and remember we are Columbia.


Alpha-fold has been successful in predicting the 3D structures of proteins from their amino acid sequences, but it's accuracy in predicting the effects of single mutations on protein stability and function remains unclear. In this study, we examined the correlation between alpha-fold's output metrics and the changes in protein stability and fluorescence, caused by single mutations. We found that there was little to no correlation between these two sets of data, suggesting that alpha-fold may not be applicable to all problems related to protein folding. This article was authored by Marina A. Pack, Karina A. Markiva, Maria S. Navacova, and others.