 Okay, we are live. So welcome to the Jenkins developer meetup session. We have Uli Haffner who will present how to beautify the user interface of your Jenkins plugins, and specifically about user interface of reportable plugins. So Uli, the floor is yours. Okay, so thank you. Okay, Oleg already introduced me. My name is Uli. I'm the author of the warnings plugin. I'm, yeah, that's, I think I'm a really long time contributor to Jenkins. I think I'm active more than 12 years now. And one of my plugins I've created in Jenkins is the warnings plugin. So just to get an impression, I've shared my screen. This is the warnings plugin. And today I will not focus on the plugin itself. I will show you how you can use the components you are seeing here in your own plugins. Or if you are not an owner of a plugin, maybe you can use one of these components to enhance any other plugin with a pre-request, for instance. So what the content of the plugins you see there is, they look a little bit different than the rest of the Jenkins plugins. And I would like to show you how you can use these components in your plugins. So to begin with, the warnings plugin started, yeah, with this new user interface by Bachelor Thesis, one of my students converted the old static analysis toolkit into a new plugin, which used a lot of new JavaScript libraries. What I have done in the last couple of months is to split these UI components into several other plugins. And here is a small component diagram. So you can see it, the warnings plugin, or it started with everything in the warnings plugin, but now I separated all these green extra components. So these components can now be used by other plugins as well. So we have e-charts, data tables, check query, et cetera. I will introduce all these new components now in the next few minutes. So these components are basically all JavaScript components. And for instance, I'll start with Fonda ASM. This is not really a library for JavaScripting, it's just a library for icons. So when I developed my plugins, I already noted I need an icon for some visualization and the Jenkins icons, we have, there was a very limited, I think we only have about 50 icons. And if you want to use some different icons, you need to get these icons somewhere. And rather than copying all these icons into a plugin, I think it would make more sense to reuse these icons for awesome, for instance. We're currently exploring on the user interface group, another icon set, the good Google material icons. So I think both icon sets can be used to improve the look and feel of Jenkins. So if you need a new icon, for instance, you just use the search box. And yeah, for instance, if you want a user icon, you just search for user. And then you see, you need to press the free button the all these icons you can use in your interface. In order to use these icons in your interface, and this is the same for all the components I will show you today. You have your counterpart Jenkins plugin. This is the font as on Jenkins plugin, which includes all these icons for you. So in order to use these icons in Jenkins, you don't need to download the JavaScript library or the sprites or the PNG icons. You just have a reference to the new font awesome Jenkins plugin. And then you can reuse these icons with a single code. So all the plugins I'm showing today are quite similar. We have a small documentation on the plugin page. So this is the GitHub plugin page for the font as an API plugin. And you will find here some examples, what you can do with the plugin and some usage guidelines. So for fonts and these icons, the usage guideline is quite simple. What we need is a dependency to this new library in the Jenkins POM. You need to add this dependency. And in order to use such an icon, you just need a jelly tech where you can use, for instance, this icon in your jelly fuse. I will show you some more details on how to use these plugins later on. So first of all, just to get the impression what different kind of plugins are available. So the font asm plugin is, yeah, just simply just provides fonts. Uli? Yeah. Is there a catalog then of the font awesome icons that are available inside the plugin? Or is that what you're seeing here? Yeah, no, this isn't just a subset. We have the catalog is available online on the font asm side. So all the things in the free set here are included in the Jenkins plugin. It's 1,588. So even for, you can search for COVID and you find some new icons if you need to use them. So it's really a lot of icons. So there are also some vendor icons like, so GitHub, and so this is really nice because normally you have a little bit problems with licensing and so this is a free font which can be used by open source projects. And yeah, I used a lot of these icons in my plugin because yeah, developing icons is quite hard. And it's better if you have some to choose from. So this is the simplest component. It has no logic in it, just some icons. The next component I would like to show is a more complex component. This is the charting library I'm using to display trend charts. This charting library is also only in JavaScript. That means everything is rendered on the client side. And currently in Jenkins, all charts are rendered on the master node which is some kind of heavy because yeah, if you have a large project and a lot of client requests to the master, then it's really hard that the master needs to deliver all these PNG images. With this library, of course we need the master as well to at least get the data from it but the rendering, if it's in small images or large images is all done on the client side using this JavaScript library. The number of charts is enormous. So just give you a impression you can have everything what you want. What I'm using currently is the pie chart, a donut chart and some line charts. But they're a student of mine used some kind of scattered charts. So there are all possibilities you can use. So this is the library I'm using and this library is also provided by an companion plugin. This is the eCharts API plugin. And this plugin is quite similar to the the font asm plugin. It bundles the JavaScripting library and it adds some more additional classes to write charts within Java. So maybe it would be it's a little bit clearer if we switch one moment to the architecture of Jenkins. So Jenkins is on the left side here, the server side we are running in chatty. Most users are running in chatty so we have somehow Jenkins core and a lot of other plugins and the warnings plugin is running within Jenkins. And now if you want to show charts within Jenkins, you need this eCharts API plugin which is deployed on Jenkins server side. And when you deploy this plugin you also get the counterpart on the client side on your laptop. That means you're in a browser in Chrome or in Firefox, it doesn't matter. Then you get these JavaScripting libraries. And what you also get, this is not shown here, you get a kind of data model within Java. That means you don't need to create charts using some JavaScript things or just the JSON model you can have charts rendered within Java. This is I will show later in the demo. So with eCharts, I think everything you need when you want to draw charts is available here. So it's really powerful. I also think it's quite impressive. For instance, we have here a chart where you have to zoom. This is nothing you need to program on your own. You just can use it, it's built in. We have the possibility for instance to toggle by date where you see the build results are now shown not on the build number rather on the date you achieve warnings or not. So it's kind of flexible, these tools. And yeah, if you need some other charts, for instance here, you can simply switch a line chart or a new worth of fixed warnings chart. So there are a lot of different options available if you use this eCharts library. The next component with I also introduced is bootstrap. I think Jenkins already includes bootstrap, at least some parts of it, a bootstrap three. What I'm using now is bootstrap four. And I think within the next couple of weeks, bootstrap five is arriving. So this is a really big and large component library to create, yeah, nice JavaScripting user interfaces. So what I'm using is not so many details up to now, but just to show you a little bit of things what you can do, there are a lot of components one can use. So we have for instance a Carousel, which I'm using where your hand can switch between the slides. You can have a drop downs, et cetera. There are really many features that you can use. I must say, I don't use so many features up to now. So what I'm using is cards. So to present results a little bit in some nicer use interface, let's see the example. So these things you see is a severities distribution or the reverence comparison. These are cards which have a nice border. And yeah, what we also have is these Carousels here where you can switch between different things. This is also provided by bootstrap. And there are many, many other things. Actually, I'm not aware already. So there are so many things you can reuse if you use this component. So you did not have to create explicit code to do the complicated switching that happens in that Carousel. It's all bootstrap for you. Yeah, that's true. Everything is annotated with diffs where you have some IDs and bootstrap is already doing the switching for you. In order to use bootstrap, it's the same again, you need my plug-in, the corresponding bootstrap for Jenkins plug-in. And this plug-in, yeah, basically provides you the JavaScripting part, the CSS part and the model which is behind some of these components. One thing what is quite interesting for bootstrap, it is already providing two very important things when you design new user interfaces. So one thing is it provides a layout grid. In Jenkins, we already use bootstrap three grid and I'm using the same thing with bootstrap four and it looks a bit boring maybe here, but the grid just divides the screen into 12 columns and with this grid, you can place any component within this grid by saying, okay, it should be here, it position, for instance, you can say, okay, the first six columns should be filled by this content and the next six columns should be filled by this. So you can basically create, I showed you in the examples to say, okay, this is, I think it's four columns, this is four columns and this is eight columns and this block on the bottom is all 12 columns. So you can create different user interfaces using this grid and it works here quite easily. So maybe you can have a look at another example. This is another plug-in I'm using in my, during my university courses to automatically create a student assignments. So when the students fill up their solutions, they get a score from me, which counts the number of failed unit tests, the code coverage, the pit mutation coverage and static analysis results. And these five boxes are also distributed with the bootstrap grid and bootstrap even is, I'm not sure if it's now visible if I switch the screen. Do we see still the Chrome browser? Okay, fine. So what you see the layout automatically changes and what you have with bootstrap, you can define different layouts for different screen resolutions. For instance, when you make the screen smaller, I'm not sure how. You suddenly see a totally new view arrives and this is that my screen's resolution is now, I don't know about 1500 pixels and then you can choose different user interfaces regarding the size of the screen. So it makes things quite easily to be seen on tablets or on, yeah, even on mobile phones. The problem is the rest of Jenkins is not that aware of mobile phones yet. So it's not so helpful if only one page works like that, but I think in the future, we can use these components more easily for all other Jenkins plug-ins as well. And that's why we have such hackathons because we can improve the situation a lot. Yeah, that would be really nice. So bootstrap, you did the definitional part. I want it to change from this to this style, but bootstrap handled the fact that that needed to occur and all the code complexity inside of it. Yeah, yeah, that means everything. I think I will show it later on how it looks in the jelly file. So yeah, then we can have a look how you can change that later on. You just used sort of a Jenkins keyword there. So this is actually expressed in the jelly files. This is expressed in the Jenkins UI expressions, not having to code separate JavaScript. I'm not using some. You don't need any JavaScript for bootstrap. Excellent, thank you. And we will see it later on if I show some details on how to code it. So let's see bootstrap. Yeah, a lot of components. The last component, I think, which is also quite helpful, at least for my plug-in, the warnings plug-in, I'm showing a lot of table or data. And the Jenkins tables are, let's say, quite limited. So what was very helpful to use this data tables component and this component, it provides pagination, search, ordering, a lot of different things. I'm not using everything yet, but just also a switch to the plug-in to see what you can do. You can switch between the number of entries and see only 10 entries. So you can search by text. Okay, there's nothing with error. Maybe let's search for something different. So you see if you can search, it is automatically adapting the table content while sorting. This is something Jenkins also has, but you can also collapse and expand a table column. So it's quite impressive what this thing can do for you. And actually, yeah, you don't need to write a JavaScript. The plug-in will also assist you with that part. So what we basically do is we need to write a model for this, but this is something I will show you in the source code now. So these are the four main components which I'm using in my plug-ins. That means the charting library, the bootstrap for the layout and the tables for showing such tables. One component I haven't extracted yet. So just to have a look at this, what I'm also using is Prism to render the source code. Yeah, this is on my agenda to extract it from the warnings plug-in. So it would be helpful if all of our plug-ins would use the same component here like code coverage or mutation coverage or even the workspace navigator in Jenkins where you can open the source files. It would be helpful if you could use this library to render the source code. And it looks like Prism is language-aware. So it would highlight Java correctly. Yeah, of course. And you have different themes. So yeah, everything works out of the box as well here. It's already included in the warnings plug-in and yeah, but I still need to have some work to extract it so everybody can use it. And yeah, the reason is because it's not only the JavaScript which is important, I think. I think what also is quite important is the Java model behind it. So all these plug-ins that I'm using in the warnings plug-in I have enhanced them with something which I call a model or a Java model behind it. So I'm not sure if everybody is familiar with Swing. I think Swing was one of the first components in Java or user interface components which split the user interface from the model. So we have the user interface part and on the other side we have a Java model which does nothing know about the user interface. And I'm also trying to use that part so that every chart is using a Java model and you are just writing code in Java and the user interface will show this model automatically. So you don't need to program anything different than Java. So no JavaScript is needed for the charts and the same is for the tables. I've created a Java table model class for Jenkins where you can implement these rows and columns and then everything is automatically rendered in this JavaScripting library and you just need to fill in the Java code and no JavaScripting code. So this is maybe the introduction and now I would like to show some details in the code on so we see how is everything working. So the first thing I want to show you is, let's show on this screen, this is a job view of, yeah, a job and here you see the number of builds and on the right side, yeah, this is one of the pain points in Jenkins, so many space and all charts are here on the right side and what I would like to show you is how you can create these charts with each charts and in order to do so, I need to go to IntelliJ and I'll switch to the favorite. So I need to rearrange my screen a little bit so hopefully everybody can see the text. So I wanna start with trend charts if you are writing a floating box. So it's a little bit know how it's required to follow this session. In order to write a trend chart on the project page, you need to write a floating box.jelly file and in order to show a trend chart in it, now you only need to provide one line of code within jelly at least this line of code says, okay, I want to write a trend chart and yeah, this trend chart is defined in my charting plug-in which basically does the diffs that are required to show the trend. So this diff here is actually the trend that is rendered by each charts and in order to show the chart, we need some JavaScript but this is nothing you need to program. This is already provided for you. That means the only thing what you need to provide is the data that you need to provide is the trend model. That means on the Java side, of course, somehow the data needs to arrive and this trend model is a method within your class that shows this chart that needs to return the model and this chart is kind of easy to create that things so typically we have, let's say, a job action, this project action within Jenkins so I just switched to Jenkins back. These charts are basically the result of a job action and in order to follow it, maybe I show you one class diagram. So this one here, so it's a little bit easier to understand. So in Jenkins, we have a job and a job has a build or a run and each run contains a set of actions and the same structure we have in a plug-in. So we have a job action which renders a job and we have a build action which renders a build and each build action contains the build results for one build, for the git plug-in, we have the commits, for the warnings plug-in, we have the warnings and for the code coverage plug-in, we have the coverage results. So this is the structure we need and for this job action, we actually generate the job graph and in order to generate the graph, we need to implement one method and this is the lines chart model of method and yeah, I can show you some details how this looks like. Maybe it's easier to see how such a chart is generated. So this is, sorry, this is the pie chart, wrong chart. So let's show you an action that shows some information about the git commits in your job and in order to create such a chart, you need to create somehow in Java the trend chart. So I think I can show you the implementation because it's quite simple. I think the details within one hour, it's really hard to show all the details just to give you an impression. So in order to create a chart, we need to define the access labels, we need to define the build numbers that are available and then we need to create some kind of a series which contains all the points we want to show and this is everything you need to write in Java. So in order to create such a charts, you need to write one chart Java class and what you also need is one, let's say a serious data where you can say, I want one class that plots one point in my chart. So maybe I show you it's on the screen. So in order to plot here, we have two points on build 59 and here we have all the two for the build 50. That means I need a class that has as input the build number and the build result from the warnings plugin and it needs to produce two values and here the values are 10 or eight and let's say six for low warnings and two normal warnings. So everything you can encode in Java, that means you have this line series where you create all these lines that are visible and you need to plot every point here. So I think it's a little bit hard to describe here without going into detail. So I think if you're interested in writing charts, you need to go afterwards into the source code and write your chart on your own. The important or what's quite helpful is everything in these charts. Let's show you in more detail. Are you, sorry, the wrong screen. So yeah, let's show these charts. Let's navigate to the source. So here are all my charts. For instance, to show a new versus fixed warnings where you see how many new warnings you have in a build and how many fixed warnings you have in the build, you need a new versus fixed builder and this builder is quite simple. It just has a couple of lines. So the input is a build result. In this case, this is the build result of the static analysis result. If you are plotting something unit tests, you have a unit test result or if you are plotting something different, you have a different instance here because it's generalized here. And what I just want to compute is I have one series for the new warnings and one series for the fixed warning. So I've just have two points and I will get automatically invoked by my framework. So the only thing what you need to provide is such a class that basically plots two points in the chart and what my plugin does, it calls you for every build where there are results available and creates the aggregation as a chart. So I'm also using this library in my testing courses in the university. So I think it takes a little bit to understand everything and to see how you can plot these charts. But I think if you get the point, it's quite simple. But of course, there still is a lot of abstraction in it. So you need to have a little bit details, you need to look into until you understand everything. So in order to use this chart, this was the beginning of the talk, you need to add this thing in the floating box where you need to define the user interface. And the second thing you need to do is to provide the Java model behind these charts. So I think basically all charts are quite similar. The pie charts are much simpler because a pie chart just contains a couple of values which are shown in a circle. So in order to create a pie chart, you don't need to have a series. You just have, for instance, here, we have a pie chart where you show, let's also show it on the example where we have the new warnings, sorry, the red ones are the new warnings and the yellow ones are the outstanding warnings and fixed warnings are not available here. In order to create this chart, you need to create such a class that has three points or points or data models where we have the message which is shown in user interface and the value which is shown to create the number and everything else is automatically rendered here by the plugin. So the tooltip, what you see here is what is here in the new warnings short message. So pie charts or line charts are quite easily to create and what you also have, maybe you can see it here. You can also create tests for it. That's also quite simple now. If you have it all in Java, you have no Java scripting which you see. So everything you can write, you can also create a tests for and that helps to improve the quality of your plugin as well. So this is the charting part. So I'm not sure if there are questions, I would show you some other details. For instance, the bootstrap part. So what to do? So I'm just a little incredulous, forgive. I'm used to thinking that if I'm gonna get a pretty user interface, it's going to have JavaScript and a pretty user interface with JavaScript means it's almost untestable to me as a Java programmer. But you just said that I as a Java programmer can use these components and deal with them in Java and it will abstract away from me having to worry about checking all the details of how the JavaScript behaves, et cetera. That's covered. That's covered, yeah. Excellent. So you can, if you want to have a look at the plugin itself, so I never, if you have, you can have a look at the warnings plugin and there is also the code coverage link and you can go into details and then you have this, let's say this charting component where you see everything which is rendered in the charts is almost by 100% code coverage and the only thing which is not tested is the Java script part which is given by the framework. So this is something a plugin author does not need to look at. So you can focus on the model and everything else should be done by the framework for you. That's excellent. Thank you. So let's go back to some different user interfaces. So one thing we talked in the beginning was on how to arrange everything on the screen with bootstrap and I show you how you can do it here in, yeah, in one layout. And first of all, I show it the screen in, so in order to create this screen, I need to, in order to create this screen you need to provide a jelly file that renders this screen. So the corresponding jelly file for this screen is shown here. And in order to use bootstrap grid, you need to provide your whole user interface in such kind of a fluid container which is driven by classes. So you don't need to program anything, you just say, okay, my whole screen is within this container. And then you can say normally you can click it here, maybe not in the presentation mode. This is, for instance, is the first row here. That means these five components are within one row. So we can define this row here. That means everything is in one row. And then we have, it's a little bit complex. We have another row and so on. So you can, first of all, divide the screen into rows and bootstrap will arrange these rows. You can define the gap between the rows. So maybe it's helpful. Let me show you in the real screen. So, so this is the thing which is rendered afterwards. So there is no way to make the font here bigger, but I can just change these values here so you can get a better padding, for instance. So let's, yeah, it's a little bit too big, but so you can, everything changed just by classes here. And what you also define here is, I want to show the next row within 12 columns, for instance. And I go back to the, so what you show, I want to show you, you can show it in 12 columns or, and now you can create different settings for different screen layout sizes. So if you want to show it on an L screen, and this is what we see now, that this box is 12 columns big. And if I scale it back one smaller, I am in the XL thing. And now it means, okay, I want to, all columns should be equal sized. And you can have totally different things. So for instance, you have here, okay, I want to have six columns, if it's a medium display, large display, six columns and so on, you have a really great flexibility to change the layout you need in your screen. You even have the chance to totally show different things. So as you've seen here, I've shown five individual charts if the screen is large enough, but if you are on a smaller screen, it's just one thing you see, or another example for the warnings plug-in. So here, for instance, we have this accordion or this carousel, but if I make the screen normal, look on my screen, then we have two charts which are shown side by side. So there you have a lot of possibilities. And I must admit that I am using just two different ones personally on my laptop. I'm using a different resolution than when I'm using my monitor. So the warnings plug-in currently is optimized for these two devices. So if you would like to provide a pull request for your screen resolution, please go ahead. And this is one perfect idea for this week to provide a pull request just to provide a different user interface for different screen resolutions. So I don't know how it looks. If you look on an iPad, for instance, maybe it would make sense to hide this chart altogether. I don't know. So these are things you have in your hand. And this is really the hard work because normally you need, I'm just a single developer, but yeah, I'm not sure how Cloudbees is doing this, but normally you need a lot of different displays and need to adapt the screen to different displays. So this is really a tough work and a lot of work to do. Yeah, I'm thinking about my Chromebook that is a 13-inch screen and tiny and limited by boundaries in all sorts of ways. Thank you. And you're interested in different proposals for layouts for those varying geometries. So this is a small part of what you can do with Bootstrap. I already said that I'm using just, I don't know, 5% of Bootstrap. So one thing I'm using is these cards. And these cards, I already provided a tag in Jelly for you. So if you want to show something in a card where you have a title and a font asm icon here on the right and something in the middle, then you can use this Bootstrap card tag where you have the title and the icon and everything else is shown automatically for you. So there's no code involved, just one new tag that you need to do here. Also to create such progress charts here, I'm not here, sorry on the out here. In order to create these charts, you just have one tag here where everything else is already done for you. So I think for these things that I'm using from Bootstrap and from the charting library, there is a Java model available. But for all other things, you need to provide the model first. So if you don't use the same charts, you need to have some extra work. But the idea is to include even more charts if they are required to. So yeah, it is an ongoing project of course. So the last thing I think would make sense to show a little to show a little bit is how the tables are working. So tables, you have basically two ways to show tables. The first way is the, yeah, let's say old school Jenkins way you create tables using diffs and spans and yeah, sorry, this is the wrong thing. Let me, yeah, sorry, I was in the wrong file. So the normal way, or the old school way in Jenkins is to create a table ahead and then we have some kind of for each loop where you can create with telly these tables. I'm using this approach as well. And this approach works also with the data tables component. That means these tables here, they are all created using a jelly files. No data, yeah, JavaScript is a well required. So the only thing is at the bottom, yeah, one call is, yeah, actually it's required. It's not really hard, but you need to create this data table. So this is the only JavaScript code you need to call. And then this plain old HTML table will automatically be converted into a data table. So the result, if we, let's say, the fixed warnings, now I'm not here, wrong one. Let's see where we have some fixed warnings. So here we have a lot of fixed warnings, that means built 64. And here we have a lot of fixed warnings. And if we select the fixed warnings, you see this table. And this is a, the data table and it is written in plain HTML. So I have nothing, or the only JavaScript is this part here at the bottom. And it is just required so that the data, or the data tables library can take this table and enhance it. So everything with searching, if you search for, this is everything out of the box given for you, and you don't have to do anything else. You simply can create your tables in your, in the way you did before, and just use this kind of thing as a kind of decorator. And everything else will be done automatically for you. So this is one way you can use it. And the other way you can use it, you can use a Java model behind it. This is how I am using it for the rest of the tables. So these tables you see here, these are built with a Java model behind it. And the model you see here is, you need to derive from this details table. Which is adapted from the swing table models. And what you basically need to provide is an ID. So we find it in the screen. And we need to define the columns. So which kind of columns do you have? For instance, we have file column packages and severities and the age column. So this is for every column, we have some kind of column definition where we say, which is the ordering, what is the content, et cetera. That means this is the thing we need to provide. And then we need to provide the rows as data. And each row is given by a Java object. So here are issues row. And these rows are quite of primitive. It's kind of data transfer object. So you have here package name, category type and severity, which is everything you see here in this row. So in order to create a table model, you need to write simply such a Java class, which returns a list of these objects. So the list is done in the base class for you. So just, you need one row, which has a selection here. The issue we want to show, if you want to show some other data, you need to provide this information here in the constructor. So basically in order to provide, in order to show a table, just create this table model. So this is a table model. So if you want to show a table, just create this table model with the color definition and with the rows, which returns the results. It has also an advantage that you can test everything. So you can provide or create the model using cheer unit tests. So everything you show in the user interface is perfectly tested if you use it this way. So you see, if you have some complex data, you can use a data model behind it. But you still, if you like, can create jelly fuse in the old school way where you mix model and user interface using for each in the jelly file. I don't like this approach because it mixes the user interface with the model. But yeah. So these were all these components I wanted to show. Now we have all four components seen. So yeah. Are there any additional questions I need to answer? I know it's a lot of heavy stuff. And you actually will notice the details only if you really program it in your own plug-in. So I'm open for questions afterwards. We are the chat or we are the mailing list or a GitHub channel. So are there any questions I can answer now? Not for me. So I wanted to talk a bit about using JavaScript for Jenkins configuration pages. So it was out of scope for this presentation. But if someone is interested, we could just have another session later this week. And yeah. Thanks totally for the great presentation because there is a lot of techniques. We could definitely adopt in Jenkins plugins and maybe even in the Jenkins core. No. Yeah, Jenkins core is a bit challenging. But yeah. That's true. So you've prompted me. I need to explore further that SCM forensics and SCM blames because a certain plug-in that I deal with might benefit significantly from at least some of these tabular views that you've done. But I think that there's the ability to do sorting and subsetting, searching, narrowing looks very, very attractive. Yeah. One of my students developed a plug-in to create forensics from Git. To see how, because I want to see if you want to look at warnings, you want to have a look at your files that have a lot of authors and a lot of commits. So you can search by author or sort by author or sort by commits, for instance. And this is, yeah, ongoing research, let's say. But it currently works only for Git. But I don't know if anybody is using a different version control system in the moment. Yes, they do. Although many systems have bridge methods for Git integration. Yeah, so we are slowly running out of time because we have another session starting just in three minutes. So I suggest to close it down and continue in the chat. Okay. So thanks again to William for a great demo. Yeah. Thanks for following me. Thank you very much, Uli. That was wonderful. Yeah. Good to hear. Okay. Bye-bye. See you later. Bye. Thank you.