Chris Hager: PDFx update and new version release (v1.4.1)

Planet Python - Sun, 2021-04-11 20:00

PDFx is a tool to extract text, links, references and metadata from PDF files and URLs. Thanks to several contributors the project received a thorough update and was brought into 2021. The new release of today is PDFx v1.4.1 🎉

PDFx works like this:

Categories: FLOSS Project Planets

GNU Guix: New Supported Platform: powerpc64le-linux

GNU Planet! - Sun, 2021-04-11 20:00

It is a pleasure to announce that support for powerpc64le-linux (PowerISA v.2.07 and later) has now been merged to the master branch of GNU Guix!

This means that GNU Guix can be used immediately on this platform from a Git checkout. Starting with the next release (Guix v1.2.1), you will also be able to download a copy of Guix pre-built for powerpc64le-linux. Regardless of how you get it, you can run the new powerpc64le-linux port of GNU Guix on top of any existing powerpc64le GNU/Linux distribution.

This new platform is available as a "technology preview". This means that although it is supported, substitutes are not yet available from the build farm, and some packages may fail to build. Although powerpc64le-linux support is nascent, the Guix community is actively working on improving it, and this is a great time to get involved!

Why Is This Important?

This is important because it means that GNU Guix now works on the Talos II, Talos II Lite, and Blackbird mainboards sold by Raptor Computing Systems. This modern, performant hardware uses IBM POWER9 processors, and it is designed to respect your freedom. The Talos II and Talos II Lite have recently received Respects Your Freedom (RYF) certification from the FSF, and Raptor Computing Systems is currently pursuing RYF certification for the more affordable Blackbird, too. All of this hardware can run without any non-free code, even the bootloader and firmware. In other words, this is a freedom-friendly hardware platform that aligns well with GNU Guix's commitment to software freedom.

How is this any different from existing RYF hardware, you might ask? One reason is performance. The existing RYF laptops, mainboards, and workstations can only really be used with Intel Core Duo or AMD Opteron processors. Those processors were released over 15 years ago. Since then, processor performance has increased drastically. People should not have to choose between performance and freedom, but for many years that is exactly what we were forced to do. However, the POWER9 machines sold by Raptor Computing Systems have changed this: the free software community now has an RYF-certified option that can compete with the performance of modern Intel and AMD systems.

Although the performance of POWER9 processors is competitive with modern Intel and AMD processors, the real advantage of the Talos II, Talos II Lite, and Blackbird is that they were designed from the start to respect your freedom. Modern processors from both Intel and AMD include back doors over which you are given no control. Even though the back doors can be removed with significant effort on older hardware in some cases, this is an obstacle that nobody should have to overcome just to control their own computer. Many of the existing RYF-certified options (e.g., the venerable Lenovo x200) use hardware that can only be considered RYF-certified after someone has gone through the extra effort of removing those back doors. No such obstacles exist when using the Talos II, Talos II Lite, or Blackbird. In fact, although Intel and AMD both go out of their way to keep you from understanding what is going on in your own computer, Raptor Computing Systems releases all of the software and firmware used in their boards as free software. They even include circuit diagrams when they ship you the machine!

Compared to the existing options, the Talos II, Talos II Lite, and Blackbird are a breath of fresh air that the free software community really deserves. Raptor Computing Systems' commitment to software freedom and owner control is an inspiring reminder that it is possible to ship a great product while still respecting the freedom of your customers. And going forward, the future looks bright for the open, royalty-free Power ISA stewarded by the OpenPOWER Foundation, which is now a Linux Foundation project (see also: the same announcement from the OpenPOWER Foundation.

In the rest of this blog post, we will discuss the steps we took to port Guix to powerpc64le-linux, the issues we encountered, and the steps we can take going forward to further solidify support for this exciting new platform.

Bootstrapping powerpc64le-linux: A Journey

To build software, you need software. How can one port Guix to a platform before support for that platform exists? This is a bootstrapping problem.

In Guix, all software for a given platform (e.g., powerpc64le-linux) is built starting from a small set of "bootstrap binaries". These are binaries of Guile, GCC, Binutils, libc, and a few other packages, pre-built for the relevant platform. It is intended that the bootstrap binaries are the only pieces of software in the entire package collection that Guix cannot build from source. In practice, additional bootstrap roots are possible, but introducing them in Guix is highly discouraged, and our community actively works to reduce our overall bootstrap footprint. There is one set of bootstrap binaries for each platform that Guix supports.

This means that to port Guix to a new platform, you must first build the bootstrap binaries for that platform. In theory, you can do this in many ways. For example, you might try to manually compile them on an existing system. However, Guix has package definitions that you can use to build them - using Guix, of course!

Commonly, the first step in porting Guix to a new platform is to use Guix to cross-compile the bootstrap binaries for that new platform from a platform on which Guix is already supported. This can be done by running a command like the following on a system where Guix is already installed:

guix build --target=powerpc64le-linux-gnu bootstrap-tarballs

This is the route that we took when building the powerpc64le-linux bootstrap binaries, as described in commit 8a1118a. You might wonder why the target above is "powerpc64le-linux-gnu" even though the new Guix platform is called "powerpc64le-linux". This is because "powerpc64le-linux-gnu" is a GNU triplet identifying the new platform, but "powerpc64le-linux" is the name of a "system" (i.e., a platform) in Guix. Guix contains code that converts between the two as needed (see nix-system->gnu-triplet and gnu-triplet->nix-system in guix/utils.scm. When cross-compiling, you only need to specify the GNU triplet.

Note that before you can even do this, you must first update the glibc-dynamic-linker and system->linux-architecture procedures in Guix's code, as described in Porting. In addition, the versions of packages in Guix that make up the GNU toolchain (gcc, glibc, etc.) must already support the target platform. This pre-existing toolchain support needs to be good enough so that Guix can (1) build, on some already-supported platform, a cross-compilation toolchain for the target platform, (2) use, on the already-supported platform, the cross-compilation toolchain to cross-compile the bootstrap binaries for the target platform, and (3) use, on the target platform, the bootstrap binaries to natively build the rest of the Guix package collection. The above guix build command takes care of steps (1) and (2) automatically.

Step (3) is a little more involved. Once the bootstrap binaries for the target platform have been built, they must be published online for anyone to download. After that, Guix's code must be updated so that (a) it recognizes the "system" name (e.g., "powerpc64le-linux") that will be used to identify the new platform and (b) it fetches the new platform's bootstrap binaries from the right location. After all that is done, you just have to try building things and see what breaks. For example, you can run ./pre-inst-env guix build hello from your Git checkout to try building GNU Hello.

The actual bootstrap binaries for powerpc64le-linux are stored on the alpha.gnu.org FTP server. Chris Marusich built these bootstrap binaries in an x86_64-linux Guix System VM which was running on hardware owned by Léo Le Bouter. Chris then signed the binaries and provided them to Ludovic Courtès, who in turn verified their authenticity, signed them, and uploaded them to alpha.gnu.org. After that, we updated the code to use the newly published bootstrap binaries in commit 8a1118a. Once all that was done, we could begin bootstrapping the rest of the system - or trying to, at least.

There were many stumbling blocks. For example, to resolve some test failures, we had to update the code in Guix that enables it to make certain syscalls from scheme. In another example, we had to patch GCC so that it looks for the 64-bit libraries in /lib, rather than /lib64, since that is where Guix puts its 64-bit libraries by convention. In addition, some packages required in order to build Guix failed to build, so we had to debug those build failures, too.

For a list of all the changes, see the patch series or the actual commits, which are:

$ git log --oneline --no-decorate 8a1118a96c9ae128302c3d435ae77cb3dd693aea^..65c46e79e0495fe4d32f6f2725d7233fff10fd70 65c46e79e0 gnu: sed: Make it build on SELinux-enabled kernels. 93f21e1a35 utils: Fix target-64bit? on powerpc64le-linux. 8d9aece8c4 ci: %cross-targets: Add powerpc64le-linux-gnu. c29bfbfc78 syscalls: Fix RNDADDTOENTCNT on powerpc64le-linux. b57de27d03 syscalls: Fix clone on powerpc64le-linux. a16eb6c5f9 Add powerpc64le-linux as a supported Guix architecture. b50f426803 gnu: libelf: Fix compilation for powerpc64le-linux. 1a0f4013d3 gnu: texlive-latex-base: Fix compilation on powerpc64le*. e9938dc8f0 gnu: texlive-bin: Fix compilation on powerpc64le*. 69b3907adf gnu: guile-avahi: Fix compilation on powerpc64le-linux. 4cc2d2aa59 gnu: bdb-4.8: Fix configure on powerpc64le-linux. be4b1cf53b gnu: binutils-final: Support more Power architectures. 060478c32c gnu: binutils-final: Provide bash for binary on powerpc-linux. b2135b5d57 gnu: gcc-boot0: Enable 128-bit long double for POWER9. 6e98e9ca92 gnu: glibc: Fix ldd path on powerpc*. cac88b28b8 gnu: gcc-4.7: On powerpc64le, fix /lib64 references. fc7cf0c1ec utils: Add target-powerpc? procedure. 8a1118a96c gnu: bootstrap: Add support for powerpc64le-linux.

In the end, through the combined efforts of multiple people, we slowly worked through the issues until we reached a point where we could do all of the following things successfully:

  • Build Guix manually on a Debian GNU/Linux ppc64el machine (this is Debian's name for a system using the powerpc64le-linux-gnu triplet), and verify that its make check tests passed.
  • Build GNU Hello using Guix and run it.
  • Run guix pull to build and install the most recent version of Guix, with powerpc64le-linux support.
  • Build a release binary tarball for powerpc64le-linux via: make guix-binary.powerpc64le-linux.tar.xz
  • Use that binary to install a version of Guix that could build/run GNU Hello and run guix pull successfully.

This was an exciting moment! But there was still more work to be done.

Originally, we did this work on the wip-ppc64le branch, with the intent of merging it into core-updates. By convention, the "core-updates" branch in Guix is where changes are made if they cause too many rebuilds. Since we were updating package definitions so deep in the dependency graph of the package collection, we assumed it wouldn't be possible to avoid rebuilding the world. For this reason, we had based the wip-ppc64le branch on core-updates.

However, Efraim Flashner proved us wrong! He created a separate branch, wip-ppc64le-for-master, where he adjusted some of the wip-ppc64le commits to avoid rebuilding the world on other platforms. Thanks to his work, we were able to merge the changes directly to master! This meant that we would be able to include it in the next release (Guix v.1.2.1).

In short, the initial porting work is done, and it is now possible for anyone to easily try out Guix on this new platform. Because guix pull works, too, it is also easy to iterate on what we have and work towards improving support for the platform. It took a lot of cooperation and effort to get this far, but there are multiple people actively contributing to this port in the Guix community who want to see it succeed. We hope you will join us in exploring the limits of this exciting new freedom-friendly platform!

Other Porting Challenges

Very early in the porting process, there were some other problems that stymied our work.

First, we actually thought we would try to port to powerpc64-linux (big-endian). However, this did not prove to be any easier than the little-endian port. In addition, other distributions (e.g., Debian and Fedora) have recently dropped their big-endian powerpc64 ports, so the little-endian variant is more likely to be tested and supported in the community. For these reasons, we decided to focus our efforts on the little-endian variant, and so far we haven't looked back.

In both the big-endian and little-endian case, we were saddened to discover that the bootstrap binaries are not entirely reproducible. This fact is documented in bug 41669, along with our extensive investigations.

In short, if you build the bootstrap binaries on two separate machines without using any substitutes, you will find that the derivation which cross-compiles %gcc-static (the bootstrap GCC, version 5.5.0) produces different output on the two systems. However, if you build %gcc-static twice on the same system, it builds reproducibly. This suggests that something in the transitive closure of inputs of %gcc-static is perhaps contributing to its non-reproducibility. There is an interesting graph toward the end of the bug report, shown below:

This graph shows the derivations that produce differing outputs across two Guix System machines, when everything is built without substitutes. It starts from the derivation that cross-compiles %gcc-static for powerpc64-linux-gnu (from x86_64-linux) using Guix at commit 1ced8379c7641788fa607b19b7a66d18f045362b. Then, it walks the graph of derivation inputs, recording only those derivations which produce differing output on the two different machines. If the non-reproducibility (across systems) of %gcc-static is caused by a non-reproducible input, then it is probably caused by one or more of the derivations shown in this graph.

At some point, you have to cut your losses and move on. After months of investigation without resolving the reproducibility issue, we finally decided to move forward with the bootstrap binaries produced earlier. If necessary, we can always go back and try to fix this issue. However, it seemed more important to get started with the bootstrapping work.

Anyone who is interested in solving this problem is welcome to comment on the bug report and help us to figure out the mystery. We are very interested in solving it, but at the moment we are more focused on building the rest of the Guix package collection on the powerpc64le-linux platform using the existing bootstrap binaries.

Next Steps

It is now possible to install Guix on a powerpc64le-linux system and use it to build some useful software - in particular, Guix itself. So Guix is now "self-hosted" on this platform, which gives us a comfortable place to begin further work.

The following tasks still need to be done. Anyone can help, so please get in touch if you want to contribute!

About GNU Guix

GNU Guix is a transactional package manager and an advanced distribution of the GNU system that respects user freedom. Guix can be used on top of any system running the Hurd or the Linux kernel, or it can be used as a standalone operating system distribution for i686, x86_64, ARMv7, and AArch64 machines.

In addition to standard package management features, Guix supports transactional upgrades and roll-backs, unprivileged package management, per-user profiles, and garbage collection. When used as a standalone GNU/Linux distribution, Guix offers a declarative, stateless approach to operating system configuration management. Guix is highly customizable and hackable through Guile programming interfaces and extensions to the Scheme language.

Categories: FLOSS Project Planets

Jelmer Vernooij: The upstream ontologist

Planet Debian - Sun, 2021-04-11 18:40

The Debian Janitor is an automated system that commits fixes for (minor) issues in Debian packages that can be fixed by software. It gradually started proposing merges in early December. The first set of changes sent out ran lintian-brush on sid packages maintained in Git. This post is part of a series about the progress of the Janitor.

The upstream ontologist is a project that extracts metadata about upstream projects in a consistent format. It does this with a combination of heuristics and reading ecosystem-specific metadata files, such as Python’s setup.py, rust’s Cargo.toml as well as e.g. scanning README files.

Supported Data Sources

It will extract information from a wide variety of sources, including:

Supported Fields

Fields that it currently provides include:

  • Homepage: homepage URL
  • Name: name of the upstream project
  • Contact: contact address of some sort of the upstream (e-mail, mailing list URL)
  • Repository: VCS URL
  • Repository-Browse: Web URL for viewing the VCS
  • Bug-Database: Bug database URL (for web viewing, generally)
  • Bug-Submit: URL to use to submit new bugs (either on the web or an e-mail address)
  • Screenshots: List of URLs with screenshots
  • Archive: Archive used - e.g. SourceForge
  • Security-Contact: e-mail or URL with instructions for reporting security issues
  • Documentation: Link to documentation on the web:
  • Wiki: Wiki URL
  • Summary: one-line description of the project
  • Description: longer description of the project
  • License: Single line license description (e.g. "GPL 2.0") as declared in the metadata[1]
  • Copyright: List of copyright holders
  • Version: Current upstream version
  • Security-MD: URL to markdown file with security policy

All data fields have a “certainty” associated with them (“certain”, “confident”, “likely” or “possible”), which gets set depending on how the data was derived or where it was found. If multiple possible values were found for a specific field, then the value with the highest certainty is taken.


The ontologist provides a high-level Python API as well as two command-line tools that can write output in two different formats:

For example, running guess-upstream-metadata on dulwich:

% guess-upstream-metadata <string>:2: (INFO/1) Duplicate implicit target name: "contributing". Name: dulwich Repository: https://www.dulwich.io/code/ X-Security-MD: https://github.com/dulwich/dulwich/tree/HEAD/SECURITY.md X-Version: 0.20.21 Bug-Database: https://github.com/dulwich/dulwich/issues X-Summary: Python Git Library X-Description: | This is the Dulwich project. It aims to provide an interface to git repos (both local and remote) that doesn't call out to git directly but instead uses pure Python. X-License: Apache License, version 2 or GNU General Public License, version 2 or later. Bug-Submit: https://github.com/dulwich/dulwich/issues/new Lintian-Brush

lintian-brush can update DEP-12-style debian/upstream/metadata files that hold information about the upstream project that is packaged as well as the Homepage in the debian/control file based on information provided by the upstream ontologist. By default, it only imports data with the highest certainty - you can override this by specifying the --uncertain command-line flag.

[1]Obviously this won't be able to describe the full licensing situation for many projects. Projects like scancode-toolkit are more appropriate for that.
Categories: FLOSS Project Planets

On finishing Season of KDE: improving Kirigami docs

Planet KDE - Sun, 2021-04-11 16:14

I wrote my first Season of KDE blog-post 3 months ago… and have since forgotten to write any updates. It’s time to address that!

Since January, I’ve been working mainly on improving the documentation for Kirigami. Back then, the Develop wiki had some pages teaching newcomers how to create a Kirigami application, but these were a little disjointed and didn’t really lead readers towards any specific goal.

There were also a lot of aspects and components of Kirigami that weren’t properly documented. Some of the existing materials also needed revising in terms of style, structure, and clarity.

Tutorials Kirigami documentation in the KDE Develop site

Before Season of KDE I’d recently started tinkering with QML and Kirigami. I wanted to create a simple application that would let you count down the days towards a date, like those you can get on your phone, but without all the obnoxious ads. Since I had no real knowledge of these tools, I started following the tutorials on the KDE Develop wiki, which was a great way of finding out what the problems were with these tutorials.

I went with the idea of the date countdown app and used this as the final goal of the tutorial. If you read through the tutorials now, you’ll find that each page builds towards creating such an app. The new tutorials go over all the essentials that you would need to know to create a basic Kirigami application, covering everything from setting up the development environment, to how to use Kirigami components, to how QML signals work, and so on. Care has also been taken to explain concepts that a beginner developer might not know much about, such as the aforementioned signals. I point this out because I, as a beginner, did not know how signals worked.

These new tutorials should make it quite a bit easier for new developers to come in and learn how a chunk of KDE development works. Hopefully we’ll soon have an influx of enthusiastic new developers bringing new applications to KDE, or helping out with our existing apps!

These new tutorials can be found in the Kirigami section of the KDE Develop site. The project I had initially begun before SoK is now called DayKountdown and is part of the Plasma Mobile namespace!

DayKountdown in its starting view. Beginners

Also helpful to beginners is a new page placed at the end of the new tutorials. This page has been designed to contain everything a newcomer might need or be interested in after creating their first Kirigami application.

Kirigami-based applications for newcomers

Taking a page out of GNOME’s newcomer guide, we have a dedicated section for new contributors. Provided is a summarised list of contribution guidelines, along with active projects that we recommend new developers can contribute to. These projects are organised in terms of complexity and feature useful links where readers can learn more about them. I hope these will encourage readers to become contributors!

There are now also a number of handy links to resources readers can use to learn more about the various tools used in KDE development. We’ve linked to some of the other tutorials available on the Develop wiki, as well as more general resources available elsewhere tackling C++ and Qt. Whereas before readers would have had to search for their own resources, now they will have an index of handpicked websites where they can go and learn more.

This page can be found here.

Component pages

Another big effort has been to expand the number of component pages in the Kirigami documentation. Previously, there have only been a limited number of components explained in the wiki, and as a result, new developers were never made aware of the breadth of components offered by Kirigami. A large part of the work in this Season of KDE project has been to address this problem.

With my last SoK merge request, we will go from having 3 component pages in the wiki to having 12! A range of cool Kirigami components now have their own pages, from inline messages to overlay sheets to form layouts and more. Carl Schwan and I are still working on polishing the merge request and getting it ready, but once it lands, it will really help the documentation take shape. The wiki should become much more useful for those interested in learning more about what they can create with Kirigami.

That’s not to say Kirigami is fully documented yet. It isn’t! But I think it’s a step in the right direction.

My time as a Season of KDE participant

6 months ago, I really didn’t know how to code at all. I’d written a lot about open source in the software in the past — I’ve advocated for it for a long time — but I never really knew how any of it worked.

I still don’t know how most things work, but I can definitely say I have learned a lot about KDE. Working on the Kirigami docs has been a very fun experience, partly because creating apps is fun in and of itself, but also because I can now grasp at how some of the applications on my computer have been made. That feels like a big-brain moment.

I must also thank my mentor Carl Schwan, who has been super helpful throughout these 3 months. Whether it has been combing over my ungainly merge requests, or reviewing the code for DayKountdown, his advice has been great and it has helped me become a (slightly) better coder.

Finally, it’s extremely fulfilling to have contributed to a software project that I have been using for the longest time. Thank you for merging my MRs!!!! I am sure there will be more of them to come, and I am looking forward refactoring lots and lots of my code



Categories: FLOSS Project Planets

Andy Wingo: guile's reader, in guile

GNU Planet! - Sun, 2021-04-11 15:51

Good evening! A brief(ish?) note today about some Guile nargery.

the arc of history

Like many language implementations that started life when you could turn on the radio and expect to hear Def Leppard, Guile has a bottom half and a top half. The bottom half is written in C and exposes a shared library and an executable, and the top half is written in the language itself (Scheme, in the case of Guile) and somehow loaded by the C code when the language implementation starts.

Since 2010 or so we have been working at replacing bits written in C with bits written in Scheme. Last week's missive was about replacing the implementation of dynamic-link from using the libltdl library to using Scheme on top of a low-level dlopen wrapper. I've written about rewriting eval in Scheme, and more recently about how the road to getting the performance of C implementations in Scheme has been sometimes long.

These rewrites have a quixotic aspect to them. I feel something in my gut about rightness and wrongness and I know at a base level that moving from C to Scheme is the right thing. Much of it is completely irrational and can be out of place in a lot of contexts -- like if you have a task to get done for a customer, you need to sit and think about minimal steps from here to the goal and the gut doesn't have much of a role to play in how you get there. But it's nice to have a project where you can do a thing in the way you'd like, and if it takes 10 years, that's fine.

But besides the ineffable motivations, there are concrete advantages to rewriting something in Scheme. I find Scheme code to be more maintainable, yes, and more secure relative to the common pitfalls of C, obviously. It decreases the amount of work I will have when one day I rewrite Guile's garbage collector. But also, Scheme code gets things that C can't have: tail calls, resumable delimited continuations, run-time instrumentation, and so on.

Taking delimited continuations as an example, five years ago or so I wrote a lightweight concurrency facility for Guile, modelled on Parallel Concurrent ML. It lets millions of fibers to exist on a system. When a fiber would need to block on an I/O operation (read or write), instead it suspends its continuation, and arranges to restart it when the operation becomes possible.

A lot had to change in Guile for this to become a reality. Firstly, delimited continuations themselves. Later, a complete rewrite of the top half of the ports facility in Scheme, to allow port operations to suspend and resume. Many of the barriers to resumable fibers were removed, but the Fibers manual still names quite a few.

Scheme read, in Scheme

Which brings us to today's note: I just rewrote Guile's reader in Scheme too! The reader is the bit that takes a stream of characters and parses it into S-expressions. It was in C, and now is in Scheme.

One of the primary motivators for this was to allow read to be suspendable. With this change, read-eval-print loops are now implementable on fibers.

Another motivation was to finally fix a bug in which Guile couldn't record source locations for some kinds of datums. It used to be that Guile would use a weak-key hash table to associate datums returned from read with source locations. But this only works for fresh values, not for immediate values like small integers or characters, nor does it work for globally unique non-immediates like keywords and symbols. So for these, we just wouldn't have any source locations.

A robust solution to that problem is to return annotated objects rather than using a side table. Since Scheme's macro expander is already set to work with annotated objects (syntax objects), a new read-syntax interface would do us a treat.

With read in C, this was hard to do. But with read in Scheme, it was no problem to implement. Adapting the expander to expect source locations inside syntax objects was a bit fiddly, though, and the resulting increase in source location information makes the output files bigger by a few percent -- due somewhat to the increased size of the .debug_lines DWARF data, but also due to serialized source locations for syntax objects in macros.

Speed-wise, switching to read in Scheme is a regression, currently. The old reader could parse around 15 or 16 megabytes per second when recording source locations on this laptop, or around 22 or 23 MB/s with source locations off. The new one parses more like 10.5 MB/s, or 13.5 MB/s with positions off, when in the old mode where it uses a weak-key side table to record source locations. The new read-syntax runs at around 12 MB/s. We'll be noodling at these in the coming months, but unlike when the original reader was written, at least now the reader is mainly used only at compile time. (It still has a role when reading s-expressions as data, so there is still a reason to make it fast.)

As is the case with eval, we still have a C version of the reader available for bootstrapping purposes, before the Scheme version is loaded. Happily, with this rewrite I was able to remove all of the cruft from the C reader related to non-default lexical syntax, which simplifies maintenance going forward.

An interesting aspect of attempting to make a bug-for-bug rewrite is that you find bugs and unexpected behavior. For example, it turns out that since the dawn of time, Guile always read #t and #f without requiring a terminating delimiter, so reading "(#t1)" would result in the list (#t 1). Weird, right? Weirder still, when the #true and #false aliases were added to the language, Guile decided to support them by default, but in an oddly backwards-compatible way... so "(#false1)" reads as (#f 1) but "(#falsa1)" reads as (#f alsa1). Quite a few more things like that.

All in all it would seem to be a successful rewrite, introducing no new behavior, even producing the same errors. However, this is not the case for backtraces, which can expose the guts of read in cases where that previously wouldn't happen because the C stack was opaque to Scheme. Probably we will simply need to add more sensible error handling around callers to read, as a backtrace isn't a good user-facing error anyway.

OK enough rambling for this evening. Happy hacking to all and to all a good night!

Categories: FLOSS Project Planets

BreadcrumbsCollector: How to use code coverage in Python with pytest?

Planet Python - Sun, 2021-04-11 14:49
Basics What is code coverage?

In the simplest words, code coverage is a measure of exhaustiveness of a test suite. 100% code coverage means that a system is fully tested.

Why bother about code coverage in Python?

Theoretically, the higher code coverage is, the less defects it has. Of course, tests are not enough to catch all kinds of errors, but in this uneven battle we need all the help we can get.

From a very mechanical perspective, the codebase is composed of individual lines. Hence, a simple formula for code coverage would be (number_of_code_lines_run_at_least_once_under_tests / total_number_of lines) * 100%. It is only at first sight that this formula looks reasonable. It’s way too insufficient. For the purpose of this article, consider the following piece of code:

from dataclasses import dataclass @dataclass class Patient: age: int is_pregnant: bool = False is_regular_blood_donor: bool = False def determine_queue_position(patient, queue): # initially, we assume that a patient will just join queue position = len(queue) # there are certain groups of patients that are served without # having to wait in a queue if patient.is_pregnant or patient.is_regular_blood_donor: position = 0 return position Why focusing on just covering lines is not enough

Now, let’s assume we have a test for that:

def test_pregnancy_means_accessing_doctor_without_having_to_wait(): queue = &#91;Patient(age=25), Patient(age=44)] patient = Patient(age=28, is_pregnant=True) queue_position = determine_queue_position(patient, queue) assert queue_position == 0

This test exercises EVERY line of determine_queue_position function. According to our initial definition, we were able to get 100% code coverage with a single test. Yet this minimal test suite can be hardly called exhaustive! For example, we haven’t tested against such patients:

  • a regular blood donor
  • both pregnant and regular blood donor
  • neither pregnant nor regular blood donor

etc. Not to mention cases like a queue with one or more patients pregnant or being regular blood donor (the latter is not covered by implementation, so we won’t be focusing on it anyway).

Types of code coverage

While the original definition of code coverage is still valid (a measure of exhaustiveness of a test suite), turns out there is a tricky part. Namely, how to assess if a test suite is actually exhaustive?

Statement coverage

We already know that a naive approach with measuring executed lines of code won’t cut it. On the bright side, it is the simplest one to understand. It is formally called line or statement coverage. This one is used by default in the most complete python code coverage lib – coverage.py.

Assuming we have code in func.py and tests in test_func.py files, we can see coverage.py (+pytest-cov plugin) reports 100% code coverage:

pytest --cov func ============================ test session starts ============================= platform darwin -- Python 3.9.0, pytest-6.2.3, py-1.10.0, pluggy-0.13.1 rootdir: /Users/spb/Projects/private/bloggo/coverr plugins: cov-2.11.1 collected 1 item test_func.py . &#91;100%] ---------- coverage: platform darwin, python 3.9.0-final-0 ----------- Name Stmts Miss Cover ----------------------------- func.py 11 0 100% ----------------------------- TOTAL 11 0 100% ============================= 1 passed in 0.04s ==============================

If statement coverage is so superficial, what are better alternatives?

Branch coverage

While code indeed is composed out of lines, our execution is rarely sequential from the top to the bottom. This is because of if-statements (and similar mechanisms) that steer how the execution flows. When there is decision-making whether to do one or another thing, we call it branching. Respectively, possible code paths are called branches.

This leads us to another type of code coverage – branch coverage. It is defined as (number_of_branches_executed_at_least_once_under_tests / all_branches) * 100%. This gives us a better idea about uncovered scenarios:

pytest --cov func --cov-branch --cov-report term-missing ============================ test session starts ============================= platform darwin -- Python 3.9.0, pytest-6.2.3, py-1.10.0, pluggy-0.13.1 rootdir: /Users/spb/Projects/private/bloggo/coverr plugins: cov-2.11.1 collected 1 item test_func.py . &#91;100%] ---------- coverage: platform darwin, python 3.9.0-final-0 ----------- Name Stmts Miss Branch BrPart Cover Missing ----------------------------------------------------- func.py 11 0 4 1 93% 17-&gt;20 ----------------------------------------------------- TOTAL 11 0 4 1 93% ============================= 1 passed in 0.05s ==============================

Branch coverage told us that we miss an if-statement at line 17th evaluates to False and the next executed line is return position. Covering it is a matter of testing with a patient that’s not pregnant neither a regular blood donor:

def test_not_pregnat_teenager_not_being_blood_donor_has_to_wait_in_queue(): queue = &#91;Patient(age=15), Patient(age=33)] patient = Patient(age=13) queue_position = determine_queue_position(patient, queue) assert queue_position == 2

Running test suite again shows we are now fully covered (at least in terms of branch coverage):

pytest --cov func --cov-branch --cov-report term-missing ============================ test session starts ============================= platform darwin -- Python 3.9.0, pytest-6.2.3, py-1.10.0, pluggy-0.13.1 rootdir: /Users/spb/Projects/private/bloggo/coverr plugins: cov-2.11.1 collected 2 items test_func.py .. &#91;100%] ---------- coverage: platform darwin, python 3.9.0-final-0 ----------- Name Stmts Miss Branch BrPart Cover Missing ----------------------------------------------------- func.py 11 0 4 0 100% ----------------------------------------------------- TOTAL 11 0 4 0 100% ============================= 2 passed in 0.05s ==============================

How about other test scenarios? Python code coverage still has no clue we haven’t tested a regular blood donor.

Condition coverage

While branch coverage nicely catches if we missed specific paths of execution, it’s indifferent to specific conditions. You certainly remember that for example or is evaluated lazily – if an expression on the left side is true, then the one on the right side is not even evaluated.

# when is_pregnant is True, then the second part won't be executed! if patient.is_pregnant or patient.is_regular_blood_donor: ...

Condition coverage assumes that in order to achieve 100% code coverage, the test suite needs to check situations in which every expression is True and False. It means condition coverage will require us to:

  • the patient is not pregnant nor a regular blood donor
  • the patient is pregnant but not a regular blood donor
  • the patient is both pregnant and a regular blood donor
  • the patient is not pregnant but is a regular blood donor

A formula for this type of coverage could be (number_of_executed_bool_states_of_operands / number_of_all_operands * 2) * 100%.

Unfortunately, there is no maintained tool in Python that will measure it for you. There was a lib called instrumental but it seems it has been abandoned for years.

On the other hand, we can resort to hypothesis (property-based testing lib) to help us generate exhaustive use cases. This would be especially helpful for more of a black-box testing without looking into guts of tested function (white-box testing).

Other types of coverage

Statement-, Branch- and Condition coverage are not all types of code coverage. If you are hungry for more, see several white papers linked at the end of the article.

Installation & configuration

I am assuming you are using pytest.

Now, if you’re new to coverage and want to get your hands dirty you can get some coverage numbers fast if you:

  • pip install pytest-cov (it depends on coverage.py so it will be installed as well)

Regarding configuration, we would certainly want to enable branch coverage. We can do this (+ few other options) using e.g. setup.cfg:

&#91;coverage:run] branch = True omit = src/db/env.py,src/db/versions/* # define paths to omit &#91;coverage:report] show_missing = True skip_covered = True Good practices When to run pytest with code coverage enabled? During build (Continous Integration)

Running tests with coverage should definitely happen during builds, e.g. on Jenkins, Travis or whatever too you use. We should set some required threshold for coverage. When it’s not met (code coverage less than expected) we fail the build, e.g. pytest --cov=src/ --cov-fail-under=100 tests/. In this example, command will fail if our coverage is lower than 100%.


Just like during Continous Integration, you can instrument pytest to run coverage plugin by manually appending appropriate parameters. The other option is to configure pytest to always collect coverage when it runs by using addopts configuration in e.g. setup.cfg:

&#91;tool:pytest] addopts = --cov src/

Personally, I advise against the second option. Why? Because collecting code coverage in Python is a considerate performance hit. If you (or anyone in your team) is using Test-First approach, then extra latency becomes an annoyance. Usually, I run small parts of the test suite when working locally in TDD cycle and then manually run the whole test suite at the end with code coverage enabled.

How much code coverage is enough?

In theory the higher code coverage, the better. I think it makes no sense to set it at 80% or 90%. I think 100% is possible with a “BUT”.

The stance on code coverage that my colleague Łukasz taught me is that one should start with 100% requirement and then exclude lines where it is not possible to achieve code coverage. It can be done using # pragma: no cover comment. For example, coverage will complain about abstract base classes, which is obviously a nonsense:

class ApiFactory(abc.ABC): @abc.abstractmethod def foo_api(self) -&gt; FooApi: # pragma: no cover pass @abc.abstractmethod def bar_api(self) -&gt; BarApi: # pragma: no cover pass

There is also an option to set excluded lines in configuration of coverage.py but it’s not ideal.

Of course, the rule of 100% test coverage must be loosened in codebases where code coverage wasn’t measured before. Even then it makes sense to set the expectation high. Initially, we can also exclude parts of the code.

Is 100% code coverage an intolerable burden?

Does a pursue for 100% code coverage mean writing tests for every function/class/module? NoNo. This is a widely held myth. If function A uses function B, then to cover both of them testing function A can be sufficient. That will largely depend on their implementation, but in general, our code is organized hierarchically, forming levels of abstraction. Then measuring code coverage is an immense help to quickly show us which parts we missed.

Testing each and every code block individually is unreasonable. It effectively makes code immutable and tests very fragile. We should be starting from higher-level tests, adding low-level ones when necessary (and code coverage will give you a great hint when you need it!). Also, be aware of encapsulation and not violating it during testing.


When one wants to truly lean on their test suite, code coverage is an indispensable thing.

Although 100% code coverage may look like an unattainable goal, in my opinion, it is the only expectation that works. It really clicks when combined with TDD.

Further reading

The post How to use code coverage in Python with pytest? appeared first on Breadcrumbs Collector.

Categories: FLOSS Project Planets

Vishal Gupta: Sikkim 101 for Backpackers

Planet Debian - Sun, 2021-04-11 10:04

Host to Kanchenjunga, the world’s third-highest mountain peak and the endangered Red Panda, Sikkim is a state in northeastern India. Nestled between Nepal, Tibet (China), Bhutan and West Bengal (India), the state offers a smorgasbord of cultures and cuisines. That said, it’s hardly surprising that the old spice route meanders through western Sikkim, connecting Lhasa with the ports of Bengal. Although the latter could also be attributed to cardamom (kali elaichi), a perennial herb native to Sikkim, which the state is the second-largest producer of, globally. Lastly, having been to and lived in India, all my life, I can confidently say Sikkim is one of the cleanest & safest regions in India, making it ideal for first-time backpackers.

Brief History
  • 17th century: The Kingdom of Sikkim is founded by the Namgyal dynasty and ruled by Buddhist priest-kings known as the Chogyal.
  • 1890: Sikkim becomes a princely state of British India.
  • 1947: Sikkim continues its protectorate status with the Union of India, post-Indian-independence.
  • 1973: Anti-royalist riots take place in front of the Chogyal's palace, by Nepalis seeking greater representation.
  • 1975: Referendum leads to the deposition of the monarchy and Sikkim joins India as its 22nd state.

  • Official: English, Nepali, Sikkimese/Bhotia and Lepcha
  • Though Hindi and Nepali share the same script (Devanagari), they are not mutually intelligible. Yet, most people in Sikkim can understand and speak Hindi.


  • Nepalis: Migrated in large numbers (from Nepal) and soon became the dominant community
  • Bhutias: People of Tibetan origin. Major inhabitants in Northern Sikkim.
  • Lepchas: Original inhabitants of Sikkim

  • Tibetan/Nepali dishes (mostly consumed during winter)
    • Thukpa: Noodle soup, rich in spices and vegetables. Usually contains some form of meat. Common variations: Thenthuk and Gyathuk
    • Momos: Steamed or fried dumplings, usually with a meat filling.
    • Saadheko: Spicy marinated chicken salad.
    • Gundruk Soup: A soup made from Gundruk, a fermented leafy green vegetable.
    • Sinki : A fermented radish tap-root product, traditionally consumed as a base for soup and as a pickle. Eerily similar to Kimchi.
  • While pork and beef are pretty common, finding vegetarian dishes is equally easy.
  • Staple: Dal-Bhat with Subzi. Rice is a lot more common than wheat (rice) possibly due to greater carb content and proximity to West Bengal, India’s largest producer of Rice.
  • Good places to eat in Gangtok
    • Hamro Bhansa Ghar, Nimtho (Nepali)
    • Taste of Tibet
    • Dragon Wok (Chinese & Japanese)

Buddhism in Sikkim
  • Bayul Demojong (Sikkim), is the most sacred Land in the Himalayas as per the belief of the Northern Buddhists and various religious texts.
  • Sikkim was blessed by Guru Padmasambhava, the great Buddhist saint who visited Sikkim in the 8th century and consecrated the land.
  • However, Buddhism is said to have reached Sikkim only in the 17th century with the arrival of three Tibetan monks viz. Rigdzin Goedki Demthruchen, Mon Kathok Sonam Gyaltshen & Rigdzin Legden Je at Yuksom. Together, they established a Buddhist monastery.
  • In 1642 they crowned Phuntsog Namgyal as the first monarch of Sikkim and gave him the title of Chogyal, or Dharma Raja.
  • The faith became popular through its royal patronage and soon many villages had their own monastery.
  • Today Sikkim has over 200 monasteries.
Major monasteries
  • Rumtek Monastery, 20Km from Gangtok
  • Lingdum/Ranka Monastery, 17Km from Gangtok
  • Phodong Monastery, 28Km from Gangtok
  • Ralang Monastery, 10Km from Ravangla
  • Tsuklakhang Monastery, Royal Palace, Gangtok
  • Enchey Monastery, Gangtok
  • Tashiding Monastery, 35Km from Ravangla

Reaching Sikkim
  • Gangtok, being the capital, is easiest to reach amongst other regions, by public transport and shared cabs.
  • By Air:
    • Pakyong (PYG) :
      • Nearest airport from Gangtok (about 1 hour away)
      • Tabletop airport
      • Reserved cabs cost around INR 1200.
      • As of Apr 2021, the only flights to PYG are from IGI (Delhi) and CCU (Kolkata).
    • Bagdogra (IXB) :
      • About 20 minutes from Siliguri and 4 hours from Gangtok.
      • Larger airport with flights to most major Indian cities.
      • Reserved cabs cost about INR 3000. Shared cabs cost about INR 350.
  • By Train:
    • New Jalpaiguri (NJP) :
      • About 20 minutes from Siliguri and 4 hours from Gangtok.
      • Reserved cabs cost about INR 3000. Shared cabs from INR 350.
  • By Road:
    • NH10 connects Siliguri to Gangtok
    • If you can’t find buses plying to Gangtok directly, reach Siliguri and then take a cab to Gangtok.
  • Sikkim Nationalised Transport Div. also runs hourly buses between Siliguri and Gangtok and daily buses on other common routes. They’re cheaper than shared cabs.
  • Wizzride also operates shared cabs between Siliguri/Bagdogra/NJP, Gangtok and Darjeeling. They cost about the same as shared cabs but pack in half as many people in “luxury cars” (Innova, Xylo, etc.) and are hence more comfortable.

  • Time needed: 1D/1N
  • Places to visit:
    • Hanuman Tok
    • Ganesh Tok
    • Tashi View Point [6,800ft]
    • MG Marg
    • Sikkim Zoo
    • Gangtok Ropeway
    • Enchey Monastery
    • Tsuklakhang Palace & Monastery
  • Hostels: Tagalong Backpackers (would strongly recommend), Zostel Gangtok
  • Places to chill: Travel Cafe, Café Live & Loud and Gangtok Groove
  • Places to shop: Lal Market and MG Marg
Getting Around
  • Taxis operate on a reserved or shared basis. In case of the latter, you can pool with other commuters your taxis will pick up and drop en-route.
  • Naturally shared taxis only operate on popular routes. The easiest way to get around Gangtok is to catch a shared cab from MG Marg.
  • Reserved taxis for Gangtok sightseeing cost around INR 1000-1500, depending upon the spots you’d like to see
  • Key taxi/bus stands :
    • Deorali stand: For Darjeeling, Siliguri, Kalimpong
    • Vajra stand: For North & East Sikkim (Tsomgo Lake & Nathula)
    • Rumtek taxi: For Ravangla, Pelling, Namchi, Geyzing, Jorethang and Singtam.

Exploring Gangtok on an MTB

North Sikkim
  • The easiest & most economical way to explore North Sikkim is the 3D/2N package offered by shared-cab drivers.
  • This includes food, permits, cab rides and accommodation (1N in Lachen and 1N in Lachung)
  • The accommodation on both nights are at homestays with bare necessities, so keep your hopes low.
  • In the spirit of sustainable tourism, you’ll be asked to discard single-use plastic bottles, so please carry a bottle that you can refill along the way.
  • Zero Point and Gurdongmer Lake are snow-capped throughout the year

3D/2N Shared-cab Package Itinerary
  • Day 1
    • Gangtok (10am) - Chungthang - Lachung (stay)
  • Day 2
    • Pre-lunch : Lachung (6am) - Yumthang Valley [12,139ft] - Zero Point - Lachung [15,300ft]
    • Post-lunch : Lachung - Chungthang - Lachen (stay)
  • Day 3
    • Pre-lunch : Lachen (5am) - Kala Patthar - Gurdongmer Lake [16,910ft] - Lachen
    • Post-lunch : Lachen - Chungthang - Gangtok (7pm)
  • This itinerary is idealistic and depends on the level of snowfall.
  • Some drivers might switch up Day 2 and 3 itineraries by visiting Lachen and then Lachung, depending upon the weather.
  • Areas beyond Lachen & Lachung are heavily militarized since the Indo-China border is only a few miles away.

East Sikkim Zuluk and Silk Route
  • Time needed: 2D/1N
  • Zuluk [9,400ft] is a small hamlet with an excellent view of the eastern Himalayan range including the Kanchenjunga.
  • Was once a transit point to the historic Silk Route from Tibet (Lhasa) to India (West Bengal).
  • The drive from Gangtok to Zuluk takes at least four hours. Hence, it makes sense to spend the night at a homestay and space out your trip to Zuluk

Tsomgo Lake and Nathula
  • Time Needed : 1D
  • A Protected Area Permit is required to visit these places, due to their proximity to the Chinese border
  • Tsomgo/Chhangu Lake [12,313ft]
    • Glacial lake, 40 km from Gangtok.
    • Remains frozen during the winter season.
    • You can also ride on the back of a Yak for INR 300
  • Baba Mandir
    • An old temple dedicated to Baba Harbhajan Singh, a Sepoy in the 23rd Regiment, who died in 1962 near the Nathu La during Indo – China war.
  • Nathula Pass [14,450ft]
    • Located on the Indo-Tibetan border crossing of the Old Silk Route, it is one of the three open trading posts between India and China.
    • Plays a key role in the Sino-Indian Trade and also serves as an official Border Personnel Meeting(BPM) Point.
    • May get cordoned off by the Indian Army in event of heavy snowfall or for other security reasons.

West Sikkim
  • Time needed: 3N/1N
  • Hostels at Pelling : Mochilerro Ostillo
Itinerary Day 1: Gangtok - Ravangla - Pelling
  • Leave Gangtok early, for Ravangla through the Temi Tea Estate route.
  • Spend some time at the tea garden and then visit Buddha Park at Ravangla
  • Head to Pelling from Ravangla
Day 2: Pelling sightseeing
  • Hire a cab and visit Skywalk, Pemayangtse Monastery, Rabdentse Ruins, Kecheopalri Lake, Kanchenjunga Falls.
Day 3: Pelling - Gangtok/Siliguri
  • Wake up early to catch a glimpse of Kanchenjunga at the Pelling Helipad around sunrise
  • Head back to Gangtok on a shared-cab
  • You could take a bus/taxi back to Siliguri if Pelling is your last stop.

  • In my opinion, Darjeeling is lovely for a two-day detour on your way back to Bagdogra/Siliguri and not any longer (unless you’re a Bengali couple on a honeymoon)
  • Once a part of Sikkim, Darjeeling was ceded to the East India Company after a series of wars, with Sikkim briefly receiving a grant from EIC for “gifting” Darjeeling to the latter
  • Post-independence, Darjeeling was merged with the state of West Bengal.
Itinerary Day 1 :
  • Take a cab from Gangtok to Darjeeling (shared-cabs cost INR 300 per seat)
  • Reach Darjeeling by noon and check in to your Hostel. I stayed at Hideout.
  • Spend the evening visiting either a monastery (or the Batasia Loop), Nehru Road and Mall Road.
  • Grab dinner at Glenary whilst listening to live music.

Day 2:
  • Wake up early to catch the sunrise and a glimpse of Kanchenjunga at Tiger Hill. Since Tiger Hill is 10km from Darjeeling and requires a permit, book your taxi in advance.
  • Alternatively, if you don’t want to get up at 4am or shell out INR1500 on the cab to Tiger Hill, walk to the Kanchenjunga View Point down Mall Road
  • Next, queue up outside Keventers for breakfast with a view in a century-old cafe
  • Get a cab at Gandhi Road and visit a tea garden (Happy Valley is the closest) and the Ropeway. I was lucky to meet 6 other backpackers at my hostel and we ended up pooling the cab at INR 200 per person, with INR 1400 being on the expensive side, but you could bargain.
  • Get lunch, buy some tea at Golden Tips, pack your bags and hop on a shared-cab back to Siliguri. It took us about 4hrs to reach Siliguri, with an hour to spare before my train.
  • If you’ve still got time on your hands, then check out the Peace Pagoda and the Darjeeling Himalayan Railway (Toy Train). At INR 1500, I found the latter to be too expensive and skipped it.

Tips and hacks
  • Download offline maps, especially when you’re exploring Northern Sikkim.
  • Food and booze are the cheapest in Gangtok. Stash up before heading to other regions.
  • Keep your Aadhar/Passport handy since you need permits to travel to North & East Sikkim.
  • In rural areas and some cafes, you may get to try Rhododendron Wine, made from Rhododendron arboreum a.k.a Gurans. Its production is a little hush-hush since the flower is considered holy and is also the National Flower of Nepal.
  • If you don’t want to invest in a new jacket, boots or a pair of gloves, you can always rent them at nominal rates from your hotel or little stores around tourist sites.
  • Check the weather of a region before heading there. Low visibility and precipitation can quite literally dampen your experience.
  • Keep your itinerary flexible to accommodate for rest and impromptu plans.
  • Shops and restaurants close by 8pm in Sikkim and Darjeeling. Plan for the same.
  • a couple of extra pairs of socks (woollen, if possible)
  • a pair of slippers to wear indoors
  • a reusable water bottle
  • an umbrella
  • a power bank
  • a couple of tablets of Diamox. Helps deal with altitude sickness
  • extra clothes and wet bags since you may not get a chance to wash/dry your clothes
  • a few passport size photographs
Shared-cab hacks
  • Intercity rides can be exhausting. If you can afford it, pay for an additional seat.
  • Call shotgun on the drives beyond Lachen and Lachung. The views are breathtaking.
  • Return cabs tend to be cheaper (WB cabs travelling from SK and vice-versa)
  • My median daily expenditure (back when I went to Sikkim in early March 2021) was INR 1350.
  • This includes stay (bunk bed), food, wine and transit (shared cabs)
  • In my defence, I splurged on food, wine and extra seats in shared cabs, but if you’re on a budget, you could easily get by on INR 1 - 1.2k per day.
  • For a 9-day trip, I ended up shelling out nearly INR 15k, including 2AC trains to & from Kolkata
  • Note : Summer (March to May) and Autumn (October to December) are peak seasons, and thereby more expensive to travel around.
Souvenirs and things you should buy

Buddhist souvenirs :
  • Colourful Prayer Flags (great for tying on bikes or behind car windshields)
  • Miniature Prayer/Mani Wheels
  • Lucky Charms, Pendants and Key Chains
  • Cham Dance masks and robes
  • Singing Bowls
  • Common symbols: Om mani padme hum, Ashtamangala, Zodiac signs
Handicrafts & Handlooms
  • Tibetan Yak Wool shawls, scarfs and carpets
  • Sikkimese Ceramic cups
  • Thangka Paintings
  • Darjeeling Tea (usually brewed and not boiled)
  • Wine (Arucha Peach & Rhododendron)
  • Dalle Khursani (Chilli) Paste and Pickle

Header Icon made by Freepik from www.flaticon.com is licensed by CC 3.0 BY
Categories: FLOSS Project Planets

Quansight Labs Blog: A step towards educating with Spyder

Planet Python - Sun, 2021-04-11 10:00

As a community manager in the Spyder team, I have been looking for ways of involving more users in the community and making Spyder useful for a larger number of people. With this, a new idea came: Education.

For the past months, we have been wondering with the team whether Spyder could also serve as a teaching-learning platform, especially in this era where remote instruction has become necessary. We submitted a proposal to the Essential Open Source Software for Science (EOSS) program of the Chan Zuckerberg Initiative, during its third cycle, with the idea of providing a simple way inside Spyder to create and share interactive tutorials on topics relevant to scientific research. Unfortunately, we didn’t get this funding, but we didn’t let this great idea die.

We submitted a second proposal to the Python Software Foundation from which we were awarded $4000. For me, this is the perfect opportunity for us to take the first step towards using Spyder for education.

Read more… (2 min remaining to read)

Categories: FLOSS Project Planets

Jonathan Dowland: 2020 in short fiction

Planet Debian - Sun, 2021-04-11 06:53

Following on from 2020 in Fiction: In 2020 I read a couple of collections of short fiction from some of my favourite authors.

I started the year with Christopher Priest's Episodes. The stories within are collected from throughout his long career, and vary in style and tone. Priest wrote new little prologues and epilogues for each of the stories, explaining the context in which they were written. I really enjoyed this additional view into their construction.

By contrast, Adam Robert's Adam Robots presents the stories on their own terms. Each of the stories is written in a different mode: one as golden-age SF, another as a kind of Cyberpunk, for example, although they all blend or confound sub-genres to some degree. I'm not clever enough to have decoded all their secrets on a first read, and I would have appreciated some "Cliff's Notes” on any deeper meaning or intent.

Ted Chiang's Exhalation was up to the fantastic standard of his earlier collection and had some extremely thoughtful explorations of philosophical ideas. All the stories are strong but one stuck in my mind the longest: Omphalos)…

With my daughter I finished three of Terry Pratchett's short story collections aimed at children: Dragon at Crumbling Castle; The Witch's Vacuum Cleaner and The Time-Travelling Caveman. If you are a Pratchett fan and you've overlooked these because they're aimed at children, take another look. The quality varies, but there are some true gems in these. Several stories take place in common settings, either the town of Blackbury, in Gritshire (and the adjacent Even Moor), or the Welsh border-town of Llandanffwnfafegettupagogo. The sad thing was knowing that once I'd finished them (and the fourth, Father Christmas's Fake Beard) that was it: there will be no more.

8/31 of the "books" I read in 2020 were issues of Interzone. Counting them as "books" for my annual reading goal has encouraged me to read full issues, whereas before I would likely have only read a couple of stories from each issue. Reading full issues has rekindled the enjoyment I got out of it when I first discovered the magazine at the turn of the Century. I am starting to recognise stories by authors that have written stories in other issues, as well as common themes from the current era weaving their way into the work (Trump, Brexit, etc.) No doubt the Pandemic will leave its mark on 2021's stories.

Categories: FLOSS Project Planets

Drupal Association Journey: Pedro Cambra: DrupalCon is coming up!

Planet Drupal - Sun, 2021-04-11 06:38

DrupalCon NorthAmerica starts tomorrow, but it is still not too late to register! There will be quite interesting content and networking activities and there’s a Drupal Association Q&A session where the floor is going to be open for the community to reach out the DA board and staff.

I’ve requested to be on the line up and I’ll be participating, so if you have any questions, please take your chance!

I don’t have a massive amount of updates from this last weeks regarding my board participation. I’ve been attending the Community and Finance committee meetings and there are some outcomes from there that I’ll be publishing about soon.

I’ve requested that the board minutes page is updated more often, and I’ll remind this to the person in charge of doing so.

I am preparing some proposals that hopefully will be addressed to the board regarding some considerations and process on the disenfranchisement non Drupal association in the elections issue. I hope to have updates on that too.

Note: This blog has the comments disabled, please feel free to send me a message through my contact page if you need to discuss anything related to the community and the Drupal Association. You can also tweet at me or find me in Drupal Slack or the distributed matrix network as pcambra.


Categories: FLOSS Project Planets

hussainweb.me: Thriving on Chaos in Drupal

Planet Drupal - Sat, 2021-04-10 23:46
Today, I want to share my thoughts from a book passage related to Drupal. The book, Everyday Chaos by David Weinberger, is largely about how chaos is the new reality in today's machine-learning-driven world. In this book, Drupal is discussed in the chapter on strategy and possibility where it is contrasted with more traditional methods of product development and organizational vision. The book is amazing and insightful, and the section on Drupal was a welcome surprise.
Categories: FLOSS Project Planets

Junichi Uekawa: Wrote a timezone checker page.

Planet Debian - Sat, 2021-04-10 22:06
Wrote a timezone checker page. timezone. Shows the current time in blue line. I haven't made anything configurable but will think about it later.

Categories: FLOSS Project Planets

Charles Plessy: Debian Bullseye: more open

Planet Debian - Sat, 2021-04-10 18:21

Debian Bullseye will provide the command /usr/bin/open for your greatest comfort at the command line. On a system with a graphical desktop environment, the command should have a similar result as when opening a document from a mouse-and-click file browser.

Technically, /usr/bin/open is a symbolic link managed by update-alternatives to point towards xdg-open if available and otherwise run-mailcap.

Categories: FLOSS Project Planets

Kentaro Hayashi: Grow your ideas for Debian Project

Planet Debian - Sat, 2021-04-10 09:13

There may be some "If it could be ..." ideas for Debian Project. If idea is concreate and worth to make things forward, it should make a proposal for Project Funding.


But it is a just an idea, or no afford to act as an executor role, that idea will not be achieved.

I thought that It needs an incubator - complemental project.


I've salvaged an idea from closed MR Add proposal about "Formalize reimbursement process" (!5) · Merge Requests · Freexian SARL / Project Funding · GitLab

I'm not confident whether mechanism works, but Debian needs change.

Categories: FLOSS Project Planets

Google does not want you to tell your players about your donation page

Planet KDE - Sat, 2021-04-10 08:48

I recently updated Pixel Wheels banner image on Google Play. That triggered a review of the game: shortly after the update I received a message telling me Pixel Wheels was "not compliant with Google Play Policies". What nefarious activity does the game engage in? Sneak on users? Mine bitcoins?


Something much more terrible, as evidenced by this screenshot they sent me:

The Horror

Yes. I confess it. I added a link to my donation page within the game, depriving Google of some precious money it totally cannot survive without! How dare I?!? I am such a bad person.

Since there is no point arguing with them, I am going to have to build a Google Play flavor of the game, where this link is replaced with a link to the game page. Hopefully the Great Algorithm will accept that. We'll see.

Meanwhile you can still get the game from F-Droid or itch.io, since they do not have a problem with a link to a donation page.

Categories: FLOSS Project Planets

This week in KDE: Activities on Wayland

Planet KDE - Sat, 2021-04-10 00:17

This week the Wayland train continued barreling on, full speed ahead! We picked up a bunch of nice fixes and a big feature:

New Features

The “Activities” feature now mostly works on Wayland! There are a few remaining things to implement to make it 100% comparable to the X11 version, but that should get done in time for the next Major Plasma release (Kevin Ottens, Plasma 5.22)

Sticky Note widgets now have an option to change the font size (Shantanu Tushar, Plasma 5.22):

Bugfixes & Performance Improvements

Zooming in and out in Okular now works correctly when using the “Trim Margins” feature (Gerd Wachsmuth, Okular 21.04)

Media9 PDF movie annotations can once again be played in Okular (Albert Astals Cid, Okular 21.04)

When using Okular’s “Invert Luma/Lightness” setting, the loading page now retains its correct color (David Hurka, Okular 21.04)

Ark can now un-archive zip files with Windows-style backslashes used as path separators (João Silva, Ark 21.08)

Fixed a bug in the Breeze application style that could manifest as a big ugly black square appearing in KMail (Fabian Vogt, Plasma 5.18.8)

Fixed one way that Plasma could crash right after login (John Zimmermann, Plasma 5.21.4)

The Plasma Wayland session will no longer crash if you plug in an external screen while in a non-GUI session (e.g. a virtual terminal) (Jan Blackquill, Plasma 5.21.4)

The Bluetooth applet’s tooltip no longer displays the wrong name of the currently connected device. I originally fixed this 9 months ago in Plasma 5.19.1 but somehow the fix was never merged into Plasma 5.20, so it got broken again. That has now been corrected (me: Nate Graham with help from James John, Plasma 5.21.4)

Ultra-wide screens with a 21:9 aspect ratio are now displayed as “21:9” in System Settings’ Display Configuration page, rather than “63:27” (lol) (Felipe Kinoshita, Plasma 5.21.4)

Fixed one way that KWin could crash with certain low-power embedded GPUs (Vlad Zahorodnii, Plasma 5.21.5)

Maximized GTK app windows are no longer positioned too high in the Plasma Wayland session (Vlad Zahorodnii, Plasma 5.21.5)

Discover’s ability to show you an app’s dependencies now works again (Aleix Pol Gonzalez, Plasma 5.21.5)

Disconnecting a screen in the Plasma Wayland session no longer causes all Qt apps to crash (Vlad Zahorodnii, Plasma 5.22)

Global shortcuts are now working even on non-US keyboard layouts (Andrey Butirsky, Plasma 5.22 in conjunction with a Qt version that has this pending patch integrated)

Plasma no longer lags or hangs when displaying a massive number of tooltips for grouped Task Manager tasks (Aleksei Nikiforov, Plasma 5.22)

The kglobalaccel5 daemon can no longer block re-login by crashing on the previous log-out and then getting stuck (David Edmundson, Plasma 5.22 or Frameworks 5.82; whichever one you get first)

When using a multi-screen setup, the lock screen no longer only displays typed text on the text field of the left-most screen, even if you clicked on the text field on a different screen (Aleix Pol Gonzalez, Plasma 5.22)

The Task Manager’s “Highlight windows when hovering over tasks” feature now works in the Plasma Wayland session (David Redondo, Plasma 5.22)

Kate and other KTextEditor-based apps no longer crash if you delete an open file on disk and choose the “Close file, discarding contents” option in the warning message that appears in the app (Christoph Cullmann, Frameworks 5.82)

Fixed a rare case where Kate and other KTextEditor-based apps could crash when dragging text (Waqar Ahmed, Frameworks 5.82)

Context Menus for text fields inside Kirigami overlay sheets are no longer displayed below the sheet content (Noah Davis, Frameworks 5.82)

In Kate and other KTextEditor-based apps, the code completion pop-up no longer sometimes take up the whole screen width (Waqar Ahmed, Frameworks 5.82)

Text in Plasma tab buttons (such as in the new Kickoff menu) now gets elided when there’s not enough space, rather than overflowing (David Edmundson, Frameworks 5.82)

User Interface Improvements

Konsole’s “Edit Profile” window now displays errors inline, rather than using an ugly modal dialog window (Ahmad Samir, Konsole 21.04):

Okular’s “Continuous” mode is now considered to be a document-specific setting (like the zoom settings are), rather than a global setting (Mahmoud Khalil, Okular 21.08)

Items in the System Settings KWin Scripts now use the “pending deletion” pattern used in many other pages, whereby deleting an item only marks as it as in a “pending deletion” state and it only actually gets deleted when you click the “Apply” button (Alexander Lohnau, Plasma 5.22)

System Tray applets now receive keyboard focus when opened, so they can be interacted with using the keyboard (Eugene Popov, Plasma 5.22)

Hover buttons in the Clipboard System Tray applet’s list items are now top-aligned for tall ones, so that the trash button doesn’t shift around according to height, which makes it easy to click on that button repeatedly to manually prune your history list (me: Nate Graham, Plasma 5.22):


Discover no longer shows a huge weird rapidly-disappearing tooltip while loading the Updates page if the cursor is over any part of it (me: Nate Graham, Plasma 5.22)

The tooltip for the window decoration button used to keep a window above all others now makes its purpose more clear (me: Nate Graham, Plasma 5.22):

The previously somewhat confusing “Keyboard Indicator” applet has been renamed and given a UI overhaul to clarify what it is and what it does (Andrey Butirsky and me: Nate Graham, Plasma 5.22):


The Task Manager tooltip now visually indicates when it’s scrollable by displaying a visible scrollbar (me: Nate Graham, Plasma 5.22)

When using the systemwide double-click mode, it’s now possible to disable “click a selected file’s label to rename it” feature for desktop icons, just as it is in Dolphin (me: Nate Graham, Plasma 5.22)

Discover’s view of an app’s dependencies has received a visual overhaul and now also shows you the exact name of the package for the app in question and also groups the dependencies by installation status (Aleix Pol Gonzalez and me: Nate Graham, Plasma 5.22):

Looks like this will install all of GNOME; guess I don’t wanna do that

All the grid view pages in System Settings now sort items case-insensitively (me: Nate Graham and Alexander Lohnau, Plasma 5.22)

Plasma list items now have left and right margins that are consistent with their top and bottom margins (Noah Davis, Frameworks 5.82)

Various message dialogs throughout KDE software no longer display pointless tooltips saying, “Yes” and “No” when you hover your cursor over buttons whose own text may already be “Yes” and “No”! (me: Nate Graham, Frameworks 5.82)

Web Presence

Check out Niccolò’s video about how to set up a development environment and submit a merge request. Very handy for audiovisual learners!

…Read that as “dev env” not “ded end” lol …And everything else

Keep in mind that this blog only covers the tip of the iceberg! Tons of KDE apps whose development I don’t have time to follow aren’t represented here, and I also don’t mention backend refactoring, improved test coverage, and other changes that are generally not user-facing. If you’re hungry for more, check out https://planet.kde.org/, where you can find blog posts by other KDE contributors detailing the work they’re doing.

How You Can Help

Have a look at https://community.kde.org/Get_Involved to discover ways to be part of a project that really matters. Each contributor makes a huge difference in KDE; you are not a number or a cog in a machine! You don’t have to already be a programmer, either. I wasn’t when I got started. Try it, you’ll like it! We don’t bite!

Finally, consider making a tax-deductible donation to the KDE e.V. foundation.

Categories: FLOSS Project Planets

hussainweb.me: Drupal Podcasts (and some PHP ones)

Planet Drupal - Fri, 2021-04-09 23:47
Today's DrupalFest post is on the lighter side. I am just going to talk about some of the podcasts I listen to related to Drupal, PHP, and software development in general. I'll try to cover all the Drupal podcasts I know about. Let me know in the comments if I have missed something. As for others, I am just listing those I listen to.
Categories: FLOSS Project Planets

Matt Glaman: Watch: Nightwatch testing training to help get Olivero stable for Drupal 9.2!

Planet Drupal - Fri, 2021-04-09 22:39

I am a little late getting this blog published. The end of March and early part of April just blew right past. However, I wanted to share the recordings from the Nightwatch.js training I gave at MidCamp on March 25th. I showed folks how to run Drupal's Nightwatch.js test suite locally, with DDEV and Lando.

The workshop code is available on the Bluehorn Digital GitHub organization, with documentation. I plan to develop this for all future testing workshops and keep it open for folks to learn from outside of paid workshops. In fact, the repo runs GitHub Actions to test the various setups and executes Drupal tests – the tests run tests to test that the tests can be tested! 😵

Categories: FLOSS Project Planets

KDE Ships Frameworks 5.81.0

Planet KDE - Fri, 2021-04-09 20:00

Saturday, 10 April 2021

KDE today announces the release of KDE Frameworks 5.81.0.

KDE Frameworks are 83 addon libraries to Qt which provide a wide variety of commonly needed functionality in mature, peer reviewed and well tested libraries with friendly licensing terms. For an introduction see the KDE Frameworks release announcement.

This release is part of a series of planned monthly releases making improvements available to developers in a quick and predictable manner.

New in this version Baloo
  • [SearchStore] Explicitly narrow timestamps for range query
  • Add now mandatory args parameter to QProcess::startDetached()
  • [MetadataMover] Update filename terms when moving/renaming file (bug 433116)
  • Fix unity compile support
Breeze Icons
  • Added branches with leaves to Kmymoney icon
  • Add a few symlinks for “configure” and “help-donate” (bug 435150)
  • Add KMyMoney Pie-Chart Icon
  • Link svn-* icons to new vcs-* icons
  • Add vcs-* icons for Kate
  • Make lock icon filled status consistent (bug 244542)
  • Remove 22 brightness icons in 16 size folder
  • Fix location of brightness icons
  • Add high-brightness and low-brightness icons
Extra CMake Modules
  • ECMGenerateExportHeader: do sanity check for version argument values
  • Fix warning about wayland-scanner code arg
  • Activate activity manager asynchronously
  • Un-overload HelperProxy::progressStep() signal
  • Add loaded signal to KCModuleData to handle delayed loading
  • Un-overload KLineEdit::returnPressed(const QString &) signal => returnKeyPressed
  • Un-overload KCompletionBox::activated(const QString &) signal => textActivated
  • Un-overload KComboBox::returnPressed(const QString &) signal, by deprecating returnPressed()
  • Relicense file to LGPL-2.0-or-later
  • kconfig_compiler: Explicitly open input file for reading
  • kconfig_compiler: change how paramString() creates strings
  • Introduce KHamburgermenu (bug 368421)
  • Enable Unicode support in QRegularExpression where needed
  • Document why we close FDs
  • Make kded shut down cleanly during systemd session teardown
KDELibs 4 Support
  • KComponentData: add a link to the KF5 porting notes
  • Enable Unicode support in QRegularExpression where needed
  • Only use unistd/getuid when available
  • Don’t let kglobalaccel run if KDE_SESSION_UID mismatches
  • Make it compile with unity cmake support
  • Handle negative years in easter and pascha calculations (bug 434027)
  • Revert “avoid race condition on loading the plugin”
  • Revert “add private header to avoid extern in .cpp file”
  • Don’t register our engine per default
  • More robust handling of missing global KDE themes
  • Ensure qrc + QDir::searchPaths work for icons (bug 434451)
  • More robust and complete setup of the scaled test environment
  • Produce output with the request devicePixelRatio
  • Properly render non-square icons
  • Remove the assumption that SVG icons are squares in icon loading
  • Retain non-square icon sizes in KIconEngine::actualSize()
  • Revert icon size behavior changes
  • Align handling of non-square icons with how Qt behaves
  • FileCopyJob: fix regression when copying a data: URL
  • Handle errors during xattr copy in a more robust way
  • Port ktelnetservice away from kdeinitexec
  • Handle .theme files correctly (bug 435176)
  • Remove KCoreDirListerCache::validUrl, let the job emit error instead
  • PreviewJob: Initialize cachesSize with 0, only pass size > 0 to shmget, improve createThumbnail (bug 430862)
  • KNewFileMenu: use destination side to stat destination (bug 429541)
  • MimeTypeFinderJob: don’t put job on hold for local files
  • FileCopyJob: port to the async AskUserActionInterface
  • Fix crash in ApplicationLauncherJob(service) when service is null
  • Don’t try to get mimetypes on empty urls
  • Fix appending file extensions in KFileWidget
  • Add a humanMoment unit to Kirigami.Units
  • Make the luma conversion of a color api accessible
  • Auto fire SearchField’s accepted, with optional extra delay (bug 435084)
  • Make globaltoolbar colorset customizable
  • Lower duration to change color for ActionButton
  • Fix focus handling in OverlaySheet to be managed as one FocusScope (bug 431295)
  • BasicListItem: partially silence binding loop
  • [FormLayout] Use layout boundaries on twin layout hints (bug 434383)
  • Make SwipeNavigator only allow the active page to be focused
  • Consider Ubuntu Touch to be mobile
  • [controls/Avatar]: Get rid of ‘both point size and pixel size’ set warning
  • Remove link to deprecated ApplicationHeader
  • the visible part should always at least be as tall as item (bug 433815)
  • Fix potential crash in SizeGroup (bug 434079)
  • turn contentItemParent into a FocusScope (bug 433991)
  • Introduce KUiServerV2JobTracker
  • qtquickengine: Do not forward intermediate states
  • quickengine: Emit entryEvent signal with enum which is exposed to QML
  • Create a NewStuff.Action component, add NewStuff.Settings global
  • Less risk of infinite spinner on uninstalling KPackage based things (bug 434371)
  • Relicense files to LGPL-2.0-or-later
  • Don’t close resident notifications when action is invoked
  • Implement inline replies on Android
  • Add an inline reply notification to the example
  • Add KNotificationReplyAction for using inline-reply Notification API
  • Add a new signal to replace the now deprecated completed(bool)
  • Deprecate concept of delayed runners & related methods
  • Deprecate methods to remove matches in RunnerContext
  • Deprecate KPluginInfo::fromKPartsInstanceName, completely unused
  • Don’t warn about unsaved changes when closing if blank and unsaved (bug 391208)
  • Use QPalette::highlight for the scrollbar minimap slider (bug 434690)
  • Avoid gaps in indentation line drawing
  • Don’t use F9 & F10 as shortcuts
  • Use Okular’s QScroller settings
  • Add basic touchscreen support
  • [Vimode] Improve sentence text object
  • [Vimode] Fix paragraph text object in visual mode
  • Restrict horizontal range of cursor to avoid unintentionally wrapping (bug 423253)
  • Turn on line numbers & modification markers
  • Update remove-trailing-spaces modeline
  • Add option to keep spaces to the left of cursor when saving (bug 433455)
  • Remove unneeded options setting
  • Search: Enable Unicode support in QRegularExpression
  • [Vimode] Show search wrapepd hint for # and * motions
  • [Vimode] Use ViewPrivate::showSearchWrappedHint() for consistency;
  • Move showSearchWrappedHint() to KTextEditor::ViewPrivate
  • [Vimode] Only display “Search wrapped” message for n/N motions
  • Ensure we use unicode regex where needed
  • Fix spellcheck word detection for non-ASCII (bug 433673)
  • Fix auto-completion for non ASCII words (bug 433672)
  • Deprecate the KFind::highlight(int, int, int) signal
  • Deprecate the KFind::highlight(QString &, int, int) signal
  • Enable Unicode support in QRegularExpression where needed
KWallet Framework
  • Un-overload OrgKdeKWalletInterface::walletClosed(int) signal
  • Bump required PlasmaWaylandProtocols
  • Fix DTD check errors and a typo
  • Add the activity management protocol client implementation
  • Add MediaPause key to mapping (bug 403636)
Plasma Framework
  • Deprecate AppletScript::description()
  • [widgets/arrows] Fix viewBox size and naturalSize in SvgItems
  • Add a humanMoment unit to the various Units
  • Add PageIndicator
  • [pluginloader] Add methods to list containments using KPluginMetaData
  • Deprecate PluginLoader::listEngineInfoByCategory
  • Mark Plasma Style as internal
  • Add notes about classes that will hopefully be dropped in KF6
  • [lineedit.svg] Remove empty space around borders and use 3px corner radius
  • [PC3 TextField] set on placeholder text
  • [PC3 TextField] mirrored -> control.mirrored
  • [PC3] Refactor TextField
  • Make compositing-off margins in the panel same size of compositing on
  • widgets>lineedit.svg: remove double ring
  • Change ContrastEffect check to AdaptiveTransparency in A.T. check (bug 434200)
  • Revert recent theme changes (bug 434202)
  • Port to singleton Units
  • Respect highlighted property (bug 384989)
  • Fix size of toolbuttons
  • [DialogButtonBox] Improve implicit size behavior
Syntax Highlighting
  • LaTeX: allow Math env within another Math env
  • java: add assert and var keywords
  • cmake.xml: Updates for CMake 3.20
  • PHP: add preg_last_error_msg() function and classes that was previously a resource
  • Js: numeric separator ; fix Octal ; add new classes
  • Try to fix Qt 5.14 based compile
  • Make it possible to compile with Qt 6
  • Fix #5 and add Path style with alternate value (${xx:-/path/})
  • Python: add match and case keywords (Python 3.10)
  • Bump rust.xml to version 12
  • Do not spellcheck in Rust code
  • Markdown: add folding in sections
  • Fix BracketMatching color in Breeze Dark theme
  • Added more checking and number support
  • Added proper escaping support with error handling
  • Yet another DetectSpaces at MultiLineText
  • Removed Variable context; not needed
  • Added Error displaying for Placeables
  • Included ##Comments
  • Optimisations (DetectIdentifier, etc.)
  • Fixed Attribute handling
  • Added support for identifiers
  • Multiline text is now working
  • Added support for fluent language files
  • Add findloc Fortran function
  • exception.h: fix export header include to work in namespace-prefixed include
Security information

The released code has been GPG-signed using the following key: pub rsa2048/58D0EE648A48B3BB 2016-09-05 David Faure faure@kde.org Primary key fingerprint: 53E6 B47B 45CE A3E0 D5B7 4577 58D0 EE64 8A48 B3BB

Categories: FLOSS Project Planets