Skip to main content

a silhouette of a person's head and shoulders, used as a default avatar

Dual head? Dual Seat! Two Users at One Computer at the Same Time!

Dual Head or Multi Monitor

If you have two monitors attached to your computer then the setup is called dual head, the generic term for any number of monitors is multi-monitor.

This setup useful if a single monitor is not enough for you to see all needed windows at once. But in this setup both monitors can be used only one person at the same time.

Dual Seat or Multi Seat

If you have two monitors what about attaching one more keyboard and mouse and “split” the computer and have independent sessions for each user? That setup is called dual seat or multi seat in general.

Linux is a multi user systems from the very beginning, but normally these users either work remotely or they simply share one seat and need to cooperate who will use the computer when.

Hardware

For this multi seat solution you need a separate graphics adapter for each seat. Fortunately to save some money you can combine discrete graphics cards with an integrated one.

If you use an integrated card you might need to enable the multi graphics support in BIOS because usually when a discrete graphics card is found the integrated one is automatically disabled.

BIOS settings

:information_source: This option is vendor dependant, check your mainboard manual.

Linux

I wanted to configure a multi seat in the past, but it was really complicated. I would have to tweak the X.org config manually and there were lots of hacks to make it work.

But actually it turned out that using a modern Linux distribution like openSUSE Leap 15.0 makes this very easy!

Using the loginctl Tool

As in almost all modern Linux distributions also in the openSUSE Leap 15.0 the console is managed by the systemd login manager. To interact with it from the command line you can use a tool called loginctl.

It can handle sessions, seats and users. Let’s see which seats are defined by default:

# loginctl list-seats
SEAT            
seat0           

1 seats listed.

Now we can list all hardware devices assigned to the default seat:

# loginctl seat-status seat0 
seat0
	Sessions: *2
	 Devices:
		  ├─/sys/devices/LNXSYSTM:00/LNXPWRBN:00/input/input5
		  │ input:input5 "Power Button"
		  ├─/sys/device…LNXSYSTM:00/LNXSYBUS:00/PNP0C0C:00/input/input4
		  │ input:input4 "Power Button"
		  ├─/sys/devices/pci0000:00/0000:00:01.3/0000:02:00.0/usb1
		  │ usb:usb1
		  ├─/sys/devices/pci0000:00/0000:00:01.3/0000:02:00.0/usb2
		  │ usb:usb2
		  ├─/sys/device…2:00.1/ata2/host1/target1:0:0/1:0:0:0/block/sr0
		  │ block:sr0
		  ├─/sys/device…ata2/host1/target1:0:0/1:0:0:0/scsi_generic/sg1
		  │ scsi_generic:sg1
		  ├─/sys/device…1.3/0000:02:00.2/0000:03:04.0/0000:05:00.0/usb4
		  │ usb:usb4
		  ├─/sys/devices/pci0000:00/0000:00:03.1/0000:09:00.0/drm/card0
		  │ [MASTER] drm:card0
		  │ ├─/sys/device…000:00:03.1/0000:09:00.0/drm/card0/card0-DP-1
		  │ │ [MASTER] drm:card0-DP-1
		  │ ├─/sys/device…:00:03.1/0000:09:00.0/drm/card0/card0-DVI-D-1
		  │ │ [MASTER] drm:card0-DVI-D-1
		  │ └─/sys/device…00:03.1/0000:09:00.0/drm/card0/card0-HDMI-A-1
		  │   [MASTER] drm:card0-HDMI-A-1
		  ├─/sys/device…000:00/0000:00:03.1/0000:09:00.0/drm/renderD128
		  │ drm:renderD128
		  ├─/sys/device…i0000:00/0000:00:03.1/0000:09:00.0/graphics/fb0
		  │ [MASTER] graphics:fb0 "amdgpudrmfb"
...

The list will be very likely long as it contains all devices present in the system. Obviously all devices are currently assigned to this single seat.

Creating a New Seat

Each seat needs a master (main) device. In the list you should see the graphics card devices marked with the [MASTER] tag.

Adding Output Device

Each graphics card should have two devices, drm:card<number> and graphics:fb<number>. To create a new seat simply move these two master devices to the new seat. Use the loginctl attach seat <path> command, copy and paste the full device path from the previous list command:

# loginctl attach seat1 /sys/devices/pci0000:00/0000:00:03.2/0000:0a:00.0/graphics/fb1
# loginctl attach seat1 /sys/devices/pci0000:00/0000:00:03.2/0000:0a:00.0/drm/renderD129

You can check that the new seat is defined properly and contains the specified devices:

# loginctl seat-status seat1
seat1
        Sessions: *1
         Devices:
                  ├─/sys/devices/pci0000:00/0000:00:03.2/0000:0a:00.0/drm/card1
                  │ [MASTER] drm:card1
                  │ ├─/sys/device…000:00:03.2/0000:0a:00.0/drm/card1/card1-DP-2
                  │ │ [MASTER] drm:card1-DP-2
                  │ ├─/sys/device…:00:03.2/0000:0a:00.0/drm/card1/card1-DVI-D-2
                  │ │ [MASTER] drm:card1-DVI-D-2
                  │ └─/sys/device…00:03.2/0000:0a:00.0/drm/card1/card1-HDMI-A-2
                  │   [MASTER] drm:card1-HDMI-A-2
                  ├─/sys/device…000:00/0000:00:03.2/0000:0a:00.0/drm/renderD129
                  │ drm:renderD129
                  └─/sys/device…i0000:00/0000:00:03.2/0000:0a:00.0/graphics/fb1
                    [MASTER] graphics:fb1 "amdgpudrmfb"

Now I’d suggest rebooting the system. After reboot you should see the login screen on the both monitors. (BTW I’m using the default KDE SDDM login manager, I do not know if the other login managers support multi seat…)

Adding Input Devices

Now we need to assign also the input devices - a keyboard and a mouse. Find the keyboard and the mouse devices in the loginctl seat-status seat0 output and move them to the other seat with the loginctl attach seat1 <path> command.

It is easy if you use different keyboard and mouse models for each seat. If you use the same models then you cannot easily distinguish between the devices. In that case I suggest using the simple trial-and-error approach, just move a device to the other seat and test if it is routed to the correct monitor. If not then simply move it back to seat0 and move the other device to seat1. You do not need to reboot, you can test it immediately.

:information_source: Multimedia keyboards might have several devices, do not forget to move them all.

And That’s it!

And that’s it! Now monitor should behave as an independent login screen with separate mouse and keyboard devices. Enjoy! :smile:

The Data Persistence

The configuration is persistent, the attached devices are remembered and automatically set after reboot. You do not need to reassign the devices after each reboot.

The Drawback

There is one drawback of enabling the multi seat feature - the multi head setup does not work anymore.

To make it work back you would have to reconnect the monitors back to the same card and move the assigned devices back to the original seat. That’s quite annoying but you could possibly automate the monitor connection by an automatic HDMI switch if you use HDMI (or DVI) for connecting the monitors and some scripting…

The Use Case: Minecraft! :video_game:

With this approach you can avoid arguing who will play Minecraft. Since now you can run two Minecraft instances in separate sessions at once! :tada:

Two Minecraft instances at one computer!

It’s not obvious from the picture, but there is only one computer below the table!

a silhouette of a person's head and shoulders, used as a default avatar

zypper-upgraderepo-plugin is here

zypper-upgraderepo-plugin adds to zypper the ability to check the repository URLs either for the current version or the next release, and upgrade them all at once in order to upgrade the whole system from command line.

This tool started as a personal project when a day I was in the need to upgrade my distro quicker than using a traditional ISO image, Zypper was the right tool but I got a little stuck when I had to handle repositories: some of them were not yet upgraded, others changed slightly in the URL path.

Who knows how to Bash the problem is not exactly a nightmare, and so I did until I needed to make a step further.

The result is zypper-upgraderepo Ruby gem which can be integrated as a zypper plugin just installing the zypper-upgraderepo-plugin package.

Installing zypper-upgraderepo-plugin

Installing zypper-upgraderepo-plugin is as easy as:

  1. Adding my repo:
    sudo zypper ar https://download.opensuse.org/repositories/home:/FabioMux/openSUSE_Leap_42.3/home:FabioMux.repo
  2. Install the package:
    sudo zypper in zypper-upgraderepo-plugin

How to use it

Sometime we want to know the status of current repositories, the command zypper ref does a similar job but it is primarily intended to update the repository’s data and that slow down a bit the whole process.
Instead we can type:

$ zypper upgraderepo --check-current

To know whether or not all the available repositories are upgrade-ready:

$ zypper upgraderepo --check-next


As you can see from the example above all the enabled repositories are ready to upgrade except for the OSS repo which has a slightly different URL.

# The URL used in the openSUSE Leap 42.3
http://download.opensuse.org/distribution/leap/42.3/repo/oss/suse/
# The suggested one for openSUSE Leap 15.0
http://download.opensuse.org/distribution/leap/15.0/repo/oss/

Let’s try again overriding the URL without make any real change:

$ zypper upgraderepo --check-next \
--override-url 8,http://download.opensuse.org/distribution/leap/15.0/repo/oss/

Once everything is ok, and after performed a backup including all the repositories, it’s time to upgrade all the repository at once:

$ sudo zypper upgraderepo --upgrade \
--override-url 8,http://download.opensuse.org/distribution/leap/15.0/repo/oss/

Conclusions

That’s all with the basic commands, more information is available in the wiki page of zypper-upgraderepo gem where all the commands are intended with the only use of the gem, but installing the plugin they are also available as zypper subcommands like shown above, also a man page is available as

$ zypper help upgraderepo

the avatar of Robert Riemann

Privacy-friendly Wizard House Quiz

You also do not want to read the lengthy privacy policy https://www.pottermore.com/about/privacy and create an account, just to know your Wizard House Quiz? Here you have a privacy-friendly alternative.

Find your Wizard House

Click the button at your favourite time to learn your Wizard house!

{{ house }}

Wizard House names may be protected under some legal acts in some countries.

No personal data from this quiz is stored or transferred.

Automated Decision Making

The following formular is employed to determine your house:

this.house = this.houses[Math.floor(Math.random()*this.houses.length)]

Source Code

<div id="app">
  <form style="border: 1px solid black; padding: 5px">
    <div class="form-group row">
      <label for="staticEmail" class="col-sm-5 col-form-label">Favourite Time:</label>
      <div class="col-sm-7">
        <button v-on:click="setHouse($event)" class="btn btn-primary btn-sm" id="staticEmail">Now!</button>
      </div>
    </div>
    <div class="form-group row">
      <label for="inputPassword" class="col-sm-5 col-form-label">Your Wizard House:</label>
      <div class="col-sm-7" id="inputPassword">
        {{ house }}
      </div>
    </div>
  </form>
</div>

<script>
  var app5 = new Vue({
  el: '#app',
  data: {
    house: '',
    houses: [
      `Slytherin`,
      `Hufflepuff`,
      `Ravenclaw`,
      `Griffondor`,
    ]
  },
  methods: {
    setHouse: function (event) {
      this.house = this.houses[Math.floor(Math.random()*this.houses.length)];
      event.preventDefault();
    }
  }
  })
</script>
a silhouette of a person's head and shoulders, used as a default avatar

openSUSE.ID goes to Taipei

Perhelatan openSUSE Asia Summit 2018 tinggal menghitung hari. Perhelatan ini akan berlangsung pada 10 – 12 Agustus di National Taiwan University of Science and Technology, Taipei. Acaranya akan cukup wah sekali karena merupakan kolaborasi tiga acara. COSCUP X GNOME.Asia Summit X openSUSE Asia Summit.

Tahun ini kembali openSUSE.ID mengirim kontingen untuk memeriahkan acara. Ada 9 Pembicara dari Indonesia di openSUSE Asia Summit. Dan ada beberapa pembicara lain yang hadir untuk GNOME.Asia Summit 2018.

Daftar kontingen openSUSE Asia Summit beserta materi yang akan dibawakan adalah:

  • Mohammad Edwin | Maintaining the Good Spirit – openSUSE Indonesia Community Experience
  • Kukuh Syafaat | openSUSE Leap & Flatpak
  • Yan Arief Purwanto | Having fun with KDE: create a Plasmoid
  • Estu Fardani | How Jogja Become City of GNU/Linux User Friendly
  • Didiet Agus Pambudiono | Deployment of multi node web server, database server and storage session server with Ansible
  • Ahmad Romadhon Hidayatullah | Working and Contributing to Open Source Project via Graphic Design in openSUSE Tumbleweed
  • Rahman Yusri Aftian | Nusantara Metode Input at openSUSE
  • Tonny Adhi Sabastian | Single Sign On Services with Free/Open Source Software at Universitas Indonesia – Updating to CAS 5
  • Mohammad Rifki Affandi Z | Build your cloud file hosting using Nextcloud on openSUSE Leap 15.0
  • Darian Rizaludin
  • Joko Susilo
  • Ahmad Haris
  • Siska Iskandar
  • Iwan S Tahari

Tiket pesawat udah dibeli, Visa udah diurus, penginepan juga sudah dipesan. Tapi materi salindia masih draft semua. :D. Sampai bertemu di Taipei.

Terimakasih untuk openSUSE dan Binar Academy yang menjadi sponsor perjalanan saya.

Estu

the avatar of Federico Mena-Quintero

Logging from Rust in librsvg

Over in this issue we are discussing how to add debug logging for librsvg.

A popular way to add logging to Rust code is to use the log crate. This lets you sprinkle simple messages in your code:

error!("something bad happened: {}", foo);
debug!("a debug message");

However, the log create is just a facade, and by default the messages do not get emitted anywhere. The calling code has to set up a logger. Crates like env_logger let one set up a logger, during program initialization, that gets configured through an environment variable.

And this is a problem for librsvg: we are not the program's initialization! Librsvg is a library; it doesn't have a main() function. And since most of the calling code is not Rust, we can't assume that they can call code that can initialize the logging framework.

Why not use glib's logging stuff?

Currently this is a bit clunky to use from Rust, since glib's structured logging functions are not bound yet in glib-rs. Maybe it would be good to bind them and get this over with.

What user experience do we want?

In the past, what has worked well for me to do logging from libraries is to allow the user to set an environment variable to control the logging, or to drop a log configuration file in their $HOME. The former works well when the user is in control of running the program that will print the logs; the latter is useful when the user is not directly in control, like for gnome-shell, which gets launched through a lot of magic during session startup.

For librsvg, it's probably enough to just use an environment variable. Set RSVG_LOG=parse_errors, run your program, and get useful output. Push button, receive bacon.

Other options in Rust?

There is a slog crate which looks promising. Instead of using context-less macros which depend on a single global logger, it provides logging macros to which you pass a logger object.

For librsvg, this means that the basic RsvgHandle could create its own logger, based on an environment variable or whatever, and pass it around to all its child functions for when they need to log something.

Slog supports structured logging, and seems to have some fancy output modes. We'll see.

a silhouette of a person's head and shoulders, used as a default avatar

Pretty big side-effect

Timing and side-channels are not normally considered side-effects, meaning compilers and cpus feel free to do whatever they want. And they do. Unfortunately, I consider leaking my passwords to remote attackers prety significant side-effect... Imagine simple function.
void handle(char secret) {}
That's obviously safe, right? And now
void handle(char secret) { int i; for (i=0; i<secret*1000000; i++) ; }
That's obviously bad idea, because now secret is exposed via timing. Now, that used to be the only sidechannel for a while, but then, caches were invented. These days,
static char font[16*256]; void handle(char secret) { font[secret*16]; }
may be bad idea. But C has not changed, it knows nothing about caches, and nothing about side-channels. Caches are old news. But today we have complex branch predictors, and speculative execution. It is called spectre. This is bad idea:
static char font[16*256]; void handle(char secret) { if (0) font[secret*16]; }
as is this:
static char small[16], big[256]; void foo(int untrusted) { if (untrusted<16) big[small[untrusted]]; }
CPU bug... unfortunately it is tricky to fix, and the bug only affects caches / timing, so it "does not exist" as far as C is concerned. Canonical fix is something like
static char small[16], big[256]; void foo(int untrusted) { if (untrusted<16) { asm volatile("lfence"); big[small[untrusted]]; }}
which is okay as long as compiler compiles it the obvious way. But again, compiler knows nothing about caches / side channels, so it may do something unexpected, and re-introduce the bug. Unfortunately, it seems that there's not even agreement whose bug it is. Is it time C was extended to know about side-channels? What about
void handle(int please_do_not_leak_this secret) {}
? Do we need new language to handle modern (speculative, multi-core, fast, side-channels all around) CPUs?
(Now, you may say that it is impossible to eliminate all the side-channels. I believe eliminating most of them is well possible, if we are willing to live with ... huge slowdown. You can store each variable twice, to at least detectrowhammer. Caches still can be disabled -- row buffer in DRAM will be more problematic, and if you disable hyperthreading and make every second instruction  lfence, you can get rid of Spectre-like problems. You may get 100x? 1000x? slowdown, but if that's applied only to software that needs it, it may be acceptable. You probably want your editors & mail readers protected. You probably don't need gcc to be protected. No, running modern web browser does not look sustainable).

a silhouette of a person's head and shoulders, used as a default avatar

Dolphin and openQA and other assorted bits

Part of this post is about openQA, openSUSE’s automated tool which tests a number of different scenarios, from installation to the behavior of the different desktop environments, plus testing the freshest code from KDE git. Recently, thanks to KDE team member Fabian Vogt, there has been important progress when testing KDE software.

Testing the Dolphin file manager

Those who use KDE software, either in Plasma or in other desktop environments have at least heard of Dolphin, the powerful file manager part of KDE Applications (by the way, have you checked out the recent beta yet?). A couple of weeks ago, in the #opensuse-kde channel, Fabian mentioned the possibility of writing new openQA tests: although there are many tests already, the desktop ones are all but comprehensive given the many possible scenarios. After some discussion back and forth, the consensus was to test Dolphin as it’s a very commonly used in many everyday tasks.

The second part was thinking up what to test. Again, the idea was to focus on common tasks: navigating and creating folders, creating and removing files, and adding elements to Places (the quick-access bar on the left). The first idea also contemplated testing drag-and-drop, but unfortunately such actions aren’t yet supported by openQA, so they were put in the backlog. With these goals in mind, Fabian created a series of tests. This is what being tested:

  • Launching dolphin and creating a folder
  • Navigating in the folder and creating a text file via context menu (“Create New…”)
  • Test navigation via the breadcrumb
  • Adding the newly-added folder via Places and ensuring it shows up in other applications
  • Remove the folder and the added place

You can see the latest results of the tests for Krypton on openQA. Of course, this does not apply to only the latest unstable code: it is also working for the main distributions.

What does this mean, in practice? openQA is flexible enough to allow even complex tests with multiple operations in succession, and these tests are very useful in catching bugs early, as it has already happened in the past. That doesn’t mean you should be complacent: keep filing those bugs, either to the distro for packaging issues, or to KDE for issues related to the software.

New Krypton links

A small but welcome addition to the Krypton live images is that now the latest build is automatically symlinked to a fixed name (openSUSE_Krypton.$arch.iso, where $arch is either i686 or x86_64. This allows now to link the images directly whenever required: before this change any direct link would break due to the ISO changing name at every rebuild. Doing the same for Argon is on the horizon, but requires some more work before it will happen.

KDE Applications 18.08 beta enters KDE:Applications

As manual testing is still important, the openSUSE KDE:Applications repository now contains the KDE Applications 18.08 beta. If you’re willing to help test the beta, please download the package and file bugs for issues you encounter. In case you’re just using the repository as an add-on, you might want to hold off updating until the final release is out.

Speaking of final release… there might some slight delays in getting it to the distribution this time: part of the KDE team (Antonio, Fabian) is attending Akademy, while others (yours truly) will be away enjoying their hard-earned (?) vacation. In this case, please exercise patience and keep your pitchforks away. ;)

the avatar of Sebastian Kügler
the avatar of openSUSE Heroes

The first steps to a more modern infrastructure

Happy SysAdmin day!

Introduction

This is a small write-up of our ongoing effort to move our infrastructure to modern technologies like Kubernetes. It all started a bit before the Hack Week 17 with the microservices and serverless for the openSUSE.org infrastructure project. As it mentions, the trigger behind it is that our infrastructure is getting bigger and more complicated, so the need to migrate to a better solution is also increasing. Docker containers and Kubernetes (for container orchestration) seemed like the proper ones, so after reading tutorials and docs, it was time to get our hands dirty!

Installing and experimenting with Kubernetes / CaaSP

We started by installing the SUSE CaaSP product on the internal Heroes VLAN. It provides an additional admin node which sets up the Kubernetes cluster. The cluster is not that big for now. It consists of the admin node, three kube-master nodes behind a load balancer and four kube-minions (workers). The product was in version 2 when we started, but version 3 became available which is the one we're using right now. It worked flawlessly, and we were even able to install the Kubernetes dashboard on top of it, which was our first Kubernetes-hosted webapp.

Since the containers inside Kubernetes are on their own internal network, we needed also a loadbalancer to expose the services to our VPN. Thus, we experimented with Ingress for load balancing of the applications deployed inside Kubernetes, also successfully. A lot of experiments around deployments, scaling and permissions took place afterwards, to get us more familiarized with the new concepts, which of course ended up in us destroying our cluster multiple times. We were surprised to see though the self-healing mechanisms taking over.

Although the experiments took place only with static pages so far, it still allowed us to learn a lot about Docker itself, eg how to create our own images and deploy them to our cluster. It's worth also mentioning the amazing kctl tool, just take a look at its README to realize how much more useful it is compared to the official kubectl.

Time to move to the next layer.

Installing and experimenting with Cloud Foundry / CAP

The next step was to install yet another SUSE product, this time the Cloud Application Platform, which offers a Platform as a Service solution based on the software named Cloud Foundry. The first blocker was met here though. CAP requires a working Kubernetes storageclass, which means that we needed to have a persistent storage backend. A good solution would be to use a distributed filesystem solution like Ceph, but due to the time limitations of Hack Week, we decided to go with a simpler solution for now, and the simplest was an NFS server. The CAP installation was smooth from that point, and we managed to login to our Cloud Foundry installation via the command line tool, as well as via the Stratos webUI. A wildcard domain *.cf.mydomain.tld was also needed here.

The idea was quite straightforward here: go to your git repository, and type a simple command like: cf push -m 256M -k 512M myapp. This would deploy a new app directly to Cloud Foundry, giving it 256MB of RAM and 512MB of disk space. As a bonus, it created a domain myapp.cf.domain.tld immediately! So the benefits here were quite obvious, no need to build our own container image with the app and set up a mechanism to deploy it, and no need for the manual step of setting up a DNS. The Ingress LB for Kubernetes that was mentioned before is also obsolete now, as Cloud Foundry handles this as well. The command cf scale could also give us the ability to scale up/down (increase/decrease memory/disk) or scale in/out (increase/decrease number of instances) as well.

Time for stress testing

Hack Week 17 was over, so the next days we deployed a few static apps (and one dynamic that needed also a memcached backend), by giving them the absolute minimal disk/RAM (around 10MB ram and 10MB to 256MB disk, depending on the webapp). We triggered a number of bots that started requesting the webpages in a loop, and the results were really impressive: even with such minimal resources and only one instance running, we saw only an increase on the CPU usage to max 15%!

As a second step, we put some static webapps of low importance running in the cluster and we let them public. We're not going to reveal which ones yet though, feel free to guess :) We plan to monitor the resource usage and activity for a few days, and if everything is fine to even put some more important webapps in.

Future tasks

There are a lot of future tasks that need to be resolved before we fully hit production. First of all, as mentioned, the NFS storageclass needs to be replaced with a proper distributed filesystem solution. SUSE Enterprise Storage product is a good candidate for it. Furthermore, we'd need to integrate our LDAP server with both CaaSP and CAP accounts. Last but not least, we are very close on making dynamic webpages with relational database needs working.

The overall progress is tracked in a trello board, and of course the internal heroes documentation has more info about the setup. Volunteers are always welcome, feel free to contact us in case you'd like to jump onboard.

Thanks to anybody who helped on setting up the cluster, the SUSE CaaSP and CAP teams for replying to our tons of questions. Special thanks go to Dimitris Karakasilis and Panagiotis Georgiadis for joining me before, during and after Hack Week 17 and still being around, making this from a simple idea to a production-ready project.

On behalf of the openSUSE Heroes team,
Theo Chatzimichos

a silhouette of a person's head and shoulders, used as a default avatar

I'm going to Akademy, again


A little bit less than a month and I will be at Akademy again, KDE's annual conference. This is the place where you can meet one of the most amazing open source communities. To me it's kind of my home community. This is where I have learned a lot about open source, where I contributed tons of code and other work, where I met a lot of awesome friends. I have been to most Akademy events, including the first KDE conference "Kastle" in 2003. But I missed the one last year. I'm more than happy to be back this year in Vienna on August 11.


Akademy will start with the conference on the weekend, August 11-12. I was in the program committee this year and I think we have put together an exciting program. You will see what's going on in KDE, what the community is doing on their goals of privacy, community onboarding, and productivity, hear about the activities of KDE e.V., get to know some of the students who work as part of one of the mentoring programs such as the Google Summer of Code, and much more.

It's a special honor to me to present the Akademy Awards this year together with my fellow award winners from last year. It was hard to choose because there are so many people who do great stuff in KDE. But we have identified a set of people who definitely deserve this prize. Join us at the award ceremony to find out who they are.

Being at Akademy is always special. It's such an amazing group of people hold together by a common idea, culture, and passion. You could never hire such a fantastic group. So I feel lucky that I got and took the opportunity to work with many of these people over the years.

It's also very rewarding to see new people join the community. Akademy always has this special mix of KDE dinosaurs, the young fresh people who just joined, and everything in between. The mentoring KDE does with great care and enthusiasm pays off, with interest.

Vienna is calling. I'll quickly answer the call. See you there.