ft SYSHH#6

Haven't done one of these in a while. So here goes…

Nine Inch Nails — And All That Could Have Been — Leaving Hope

NIN have a couple of amazing instrumental tracks on their résumé, some very quiet ones too, and it's hard to pick a favourite. But if pressed for an answer, I'd pick this.

Posted Sun 20 Jan 2019 16:59:26 CET Tags:

After being the most horrible package maintainer imaginable for at least the past two years, I've been putting some work into the Debian package for the MRA/MDA combination that is fdm. That package now captures a new version control snapshot from upstream (releases happen seldom, the project is pretty much in maintenance only mode), that fixes a couple of things and adds some features, like being able to use SSL with Google's IMAP without turning off all kinds of verifications.

I've been using different iterations of the new package for a while now and am experiencing zero issues in day to day use. So even though this is the first package update in a while, and a couple of things (like the build system) have changed upstream; I'm fairly confident this is an improvement over the previous versions of the Debian package.

Internally, the packaging is pretty much a complete rewrite. It uses modern debhelper features and implements pretty much all items on Debian's wish list (like machine readable debian/copyright format and stuff like that).

Thanks go out to Axel, who patiently reviewed my changes and helped me get this package out of the door before buster goes into freeze. This update would not have happened without him.

Posted Sun 20 Jan 2019 15:26:50 CET Tags:

In my dayjob, I'm an electrical engineer. Though, I'm mostly involved in writing firmware that runs on baremetal systems. If you're designing electrical circuits for a living or just tinkered with them, you will have heard of E-Series preferred values. In particular, resistors, capacitors and inductors are generally available in ratings derived from these numbers. The basic idea is to fit a number of values into one order of magnitude. For examples in E3, there are three values in the same decimal power: 100, 220 and 470. The next value would be 1000 in the next decimal power. Likewise in E12 there are twelve such values.

Roughly, E-Series follow an exponential definition. The series generally don't follow the exact mathematical expression. For an actual implementation you either adjust to the specified values or you simply use the actual tables from the spec.

Now looking up values in tables is a boring task; especially if the tables are relatively small. Finding combinations, though, is more interesting. For example, if you'd like a resistor rated at 50Ω (which is a rather important value in radio frequency design), you'll notice that the exact value is not available in any of the E-Series. But it's easy to combine two 100Ω resistors in parallel to produce a value of 50Ω. …sure, in an actual design you might use 49.9Ω from E96 or E192, or use a specially made resistor of the desired rating. But you get the idea. Combining components in parallel and series circuits allows the parts from E-Series to cover lots of ground.

I've written a library that implements E-Series in Scheme. Its main modules are (e-series adjacency), which allows looking up values from an E-Series that are in the vicinity of a given value. Then there's (e-series combine) which produces combinations of values from a certain E-Series to approximate a given value. And finally there's the top-level (e-series) module, that implements frontends to the other mentioned modules, to make it possible to easily use the library at a Scheme REPL.

To see if the library finds a combination from E12 that matches 50Ω:

scheme@(guile-user)> (resistor 12 50)
    Desired  |         Actual (Error)  |     Part A  |     Part B  |  Circuit
   50.0000Ω  |   50.0000Ω (  exact  )  |   100.000Ω  |   100.000Ω  |  parallel
   50.0000Ω  |   50.0380Ω (+7.605E-4)  |   56.0000Ω  |   470.000Ω  |  parallel
   50.0000Ω  |   49.7000Ω (-6.000E-3)  |   47.0000Ω  |   2.70000Ω  |  series
   50.0000Ω  |   50.3000Ω (+6.000E-3)  |   47.0000Ω  |   3.30000Ω  |  series

Those aren't all the combinations that are possible. By default the module produces tables, that contain combinations that match the desired value at least as well as 1%. Now, to see values in the vicinity of 50Ω all E-Series, you can do this:

scheme@(guile-user)> (resistor 50)
  Series  |           Below (Error)  |      Exact  |           Above (Error)
    E3    |   47.0000Ω  (-6.000E-2)  |             |   100.000Ω  (+1.000E+0)
    E6    |   47.0000Ω  (-6.000E-2)  |             |   68.0000Ω  (+3.600E-1)
    E12   |   47.0000Ω  (-6.000E-2)  |             |   56.0000Ω  (+1.200E-1)
    E24   |   47.0000Ω  (-6.000E-2)  |             |   51.0000Ω  (+2.000E-2)
    E48   |   48.7000Ω  (-2.600E-2)  |             |   51.1000Ω  (+2.200E-2)
    E96   |   49.9000Ω  (-2.000E-3)  |             |   51.1000Ω  (+2.200E-2)
    E192  |   49.9000Ω  (-2.000E-3)  |             |   50.5000Ω  (+1.000E-2)

And here you see that E96 and E192 have pretty close matches as single components.

With combinations, the library allows the for user to specify arbitrarily complex predicates to choose from the generated combinations. For example, to only return parallel circuits that approximate 50Ω from E12:

scheme@(guile-user)> (resistor 12 50 #:predicate (circuit 'parallel))

And to limit those results to those that have an eror of 0.001 or better, here's a way:

scheme@(guile-user)> (resistor 12 50 #:predicate (all-of (max-error 1e-3)
                                                         (circuit 'parallel)))
    Desired  |         Actual (Error)  |     Part A  |     Part B  |  Circuit
   50.0000Ω  |   50.0000Ω (  exact  )  |   100.000Ω  |   100.000Ω  |  parallel
   50.0000Ω  |   50.0380Ω (+7.605E-4)  |   56.0000Ω  |   470.000Ω  |  parallel

There are frontends for inductors and capacitors as well, so you don't have to mentally strain yourself too much about with combination corresponds to which circuit. To find a 9.54μF capacitor approximation from E24 with an error better than 0.002:

scheme@(guile-user)> (capacitor 24 #e9.54e-6 #:predicate (max-error #e2e-3))
    Desired  |         Actual (Error)  |     Part A  |     Part B  |  Circuit
  9.54000µF  |  9.53000µF (-1.048E-3)  |  9.10000µF  |  430.000nF  |  parallel
  9.54000µF  |  9.55102µF (+1.155E-3)  |  13.0000µF  |  36.0000µF  |  series
  9.54000µF  |  9.52381µF (-1.697E-3)  |  10.0000µF  |  200.000µF  |  series

The test-suite and documentation coverage could be better, but the front-end module is easy enough to use, I think.

Posted Sun 09 Dec 2018 23:21:36 CET Tags:

At this point, Scheme is my favourite language to program in. And my prefered implementation (…there are a lot) is GNU Guile. I've written a couple of pieces of software using it: Bindings for termios on POSIX Systems, An implementation of Linear Feedback Shift Registers, A unit test framework that emits TAP output, A system that produces time-sheets from Redmine Timing exports, An elaborate system to describe and experiment with configurable electronic parts and native implementation of the XMMS2 protocol and client library. That latter I've written about before.

Now with Guile there's a lot going on. The project as a small but dedicated team of developers. And they have been working on improving the system performance by a lot. For the longest time, Guile only had an interpreter. The last version of that was 1.8 — the version I came in contact with for the first time as well. Shortly after I started to dabble, 2.0 was released so I didn't have a lot of exposure to 1.8. Version 2.0 added a stack VM that Guile byte-compiled its code to. In 2017 the project released version 2.2, which saw the stack VM replaced by a register VM. And that improved performance dramatically. And now, they are preparing a 3.0 release (2.9.1 beta release happened on October the 10th of this year), which adds just-in-time native code generation on x86-64 via GNU Lightning.

I used xmms2-guile to get an idea about the improvements that the different Guile versions offer. I couldn't be arsed to build myself a 1.8 release so, this won't look at that. The setup is a minimal client connecting to an XMMS2 server, pull out the information required to display a playlist of about 15300 tracks. All of this is running on an Intel Core i7 with plenty of memory, running XMMS2 version 0.8 DrO_o (git commit: 3bd868a9).

As a point of comparison, I ran XMMS2's command line client to do the same task. It took a mean time of 10.77 seconds. That's about 1420 tracks processed per second. I'm pretty sure the client does a little more than it needs to, but this establishes a ballpark.

With Guile 2.0 the whole affair takes 23.9 seconds. That's about 640 tracks per second. Quite a bit slower. More than twice as slow. I was sure this would be slower than the official client, but the difference is disappointing. So what about 2.2 — can it do better?

Well, in Guile 2.2 the same job takes 6.38 seconds. 2400 tracks per second! Impressive. This is why I think the official CLI client implemented in C does a little too much work than it needs. It shouldn't lose to this, and if it would, it shouldn't be behind this much. My xmms2-guile client library is a native implementation. It doesn't wrap the official XMMS2 client library that's written in C. I'm way too lazy to do detailed timing analyses of the different libraries and Scheme implementations. The results are reproducible, though.

Now what about the upcoming Guile 3.0? I've used to be precise. It should execute a little faster, but the 2.2 results are pretty good already. Running the same setup yields a mean time of 5.87 seconds. A bit over 2600 tracks per second.

I mean sure, this is not an in-depth analysis, there's a local network connection involved and it's a rather specific repetitive task. Still though. Pretty cool when a random test shows that 3.0 is four times as fast as 2.0. ;)

Posted Tue 13 Nov 2018 00:55:34 CET Tags:

I've been lazy on the arename side of things. Life. Jobs. And lots of other interests… But I guess about five and a half years is a good a time as any to release another version.

This version is mostly a bugfix release, but it also contains one major change in the way that add-on code is handled. Previously, the idea was to copy and paste stuff from examples to .arename.hooks. It was a bad idea from the start but that's how it is with programs that start out as a quick hack.

Anyway. Starting with v4.1, all previous examples (and one or the other new one) are now bundled with arename as Perl modules in the ARename::… name space. All of them contain fairly complete documentation, which users can access using perldoc:

% perldoc ARename::ReplaceSpaces

Using them is straight forward:

use ARename::ReplaceSpaces;

The new EXTENSIONS section in the manual (man arename) briefly describes the included add-ons; and the full details are available — as mentioned above — via perldoc.

Something else that sucks a little is that github removed a feature from their service in the meantime, that allowed projects to upload tar-balls for releases. That is gone entirely, which breaks arename releases a little bit. Previously, I would generate tarballs that contained pre-build modules, manual pages etc… that's gone now, so though luck.

If you are a distributor in need of such a tarball do make release to get a tarball named arename-4.1.tar.gz.

In the future, I might include a VERSION file as a fallback for when the project is not built from a git repository. That would make automatically generated tarballs from release tags via github's web interface more useful, I guess. But for now, that's what it is.

Posted Mon 24 Jul 2017 23:40:05 CEST Tags:

“…done in Scheme.” was an idea I had when I started liking Scheme more and more. XMMS2 is my preferred audio player for a long time now. And I always wanted to write a client for it that fits my frame of mind better than the available ones.

I started writing one in C and that was okay. But when you're used to use properly extensible applications on a regular basis, you kind of want your audio player to have at least some of those abilities as well. I started adding a lua interpreter (which I didn't like), a Perl interpreter (which I did before in another application, but which is also not a lot of fun). So I threw it all away, setting out to write one in Scheme from scratch.

To interface the XMMS2 server, I was first trying to write a library that wrapped the C library that the XMMS2 project ships. But now I was back to writing C, which I didn't want to do. Someone on IRC in #xmms2 on freenode suggested to just implement the whole protocol in Scheme natively. I was a little intimidated by that, because the XMMS2 server supports a ton of IPC calls. But XMMS2 also ships with machine readable definitions of all of those, which means that you can generate most of the code and once you've implemented the networking part and have the serialization and de-serialization for the protocol's data types, you're pretty much set. …well, after you've implemented the code that generates your IPC code from XMMS2's definition file.

Most of XMMS2's protocol data types map very well to Scheme. There are strings, integers, floating point numbers, lists, dictionaries. All very natural in Scheme.

And then there are Collections. Collections are a way to interact with the XMMS2 server's media library. You can query the media library using collections. You can generate play lists using collections and perform a lot of operations on them like sorting them in a way you can specify yourself. For more information about collections see the Collections Concept page in the XMMS2 wiki.

Now internally, Collections are basically a tree structure, that may be nested arbitrarily. It carries a couple of payload data sets, but they are trees. And implementing a tree in Scheme is not all that hard either. The serialization and de-serialization is also pretty straight forward, since the protocol reuses its own data types to represent the collection data.

What is not quite so cool is the language you end up with to express these collections. Say, you want to create a collection that matches four Thrash Metal groups you can do that with XMMS2's command line client like so:

xmms2 coll create big-four artist:Slayer \
                        OR artist:Metallica \
                        OR artist:Anthrax \
                        OR artist:Megadeth

To create the same collection with my Scheme library, that would look like this:

    '() '()
    (list (make-collection COLLECTION-TYPE-EQUALS
              '((field . "artist")
                (value . "Slayer"))
              (list (make-collection COLLECTION-TYPE-UNIVERSE '() '() '())))
          (make-collection COLLECTION-TYPE-EQUALS
              '((field . "artist")
                (value . "Metallica"))
              (list (make-collection COLLECTION-TYPE-UNIVERSE '() '() '())))
          (make-collection COLLECTION-TYPE-EQUALS
              '((field . "artist")
                (value . "Anthrax"))
              (list (make-collection COLLECTION-TYPE-UNIVERSE '() '() '())))
          (make-collection COLLECTION-TYPE-EQUALS
              '((field . "artist")
                (value . "Megadeth"))
              (list (make-collection COLLECTION-TYPE-UNIVERSE '() '() '())))))

…and isn't that just awful? Yes, yes it is. It so is.

In order to reign in this craziness, the library ships a macro that implements a little domain specific language to express collections with. Using that, the above boils down to this:

(collection (∩ (artist = Slayer)
               (artist = Metallica)
               (artist = Anthrax)
               (artist = Megadeth)))

So much better, right? …well, unless you really don't like Unicode characters and the ‘∩’ in there gives you a constant headache… But worry not, you can also use ‘or’ in place if the intersection symbol if you like. Or ‘INTERSECTION’ if you really want to be clear about things.

If you know a bit of Scheme, you may wonder how to use arguments to those operators that get evaluated at run time. Since evidently, the Slayer in there is turned into a "Slayer" string at compile time; same goes for the artist symbol. These transformations are done to make the language very compact for users to just type expressions. If you want an operator to be evaluated, you have to wrap it in a (| ...) expression:

(let ((key "artist") (value "Slayer"))
  (collection ((| key) = (| value)))

These expressions may be arbitrarily complex.

Finally, to traverse Collection tree data structures, the library ships a function called ‘collection-fold’. It implements pre, post and level tree traversal with both left-to-right and right-to-left directions. So, if you'd like to count the number of nodes in a collection tree, you can do it like this:

(define *big-four* (collection (∩ (artist = Slayer)
                                  (artist = Metallica)
                                  (artist = Anthrax)
                                  (artist = Megadeth)))

(collection-fold (lambda (x acc) (+ acc 1))
                 0 *big-four*)

This would evaluate to 9.

The library is still at an early stage, but it can control an XMMS2 server as the ‘cli’ example, shipped with the library, will show you. There are no high level primitives to support synchronous and asynchronous server interactions. And there is not a whole lot of documentation, yet either. But the library implements all data types the protocol supports as well as all methods, signals and broadcasts the IPC document defines. The collection DSL supports all collection operators and all attributes one might want to supply.

Feel free to take a look, play around, report bugs. The library's home is with my account on github.

Posted Sun 15 Jan 2017 15:52:39 CET Tags:

Hello dewi users! (Yes, all three of you.)

I started developing dewi in 2010. Back then I did two releases in less than a week. And now the third release gets out more than six years later. There are a number of reasons for the amount of time this took: I made a few mistakes in dewi's design, and fixing them took some effort. Spare time got really scarce. I wasted some time implementing features, that should never have been part of dewi (because they were features, my previous solution to this problem had). I wanted lots of features, that took a while to finish. Because the new release would definitely break backwards compatibility, I was working on a separate branch called “onward”, that basically only I used. And finally, since the code in that “onward” branch worked for me (I knew its shortcomings and worked around them), I could not motivate myself to fix all the outstanding issues and add proper documentation for all that had changed. Therefore nothing happened.

In the meantime, other systems like vcsh, rcm or homesick have emerged. Really, there are tons of systems like these out there, these are just a few of them that get mentioned to me more often than the others. Some of these systems hard depend on a version control system — usually git — and even have it at their absolute centre of implementation. Others just made pretty weird design decisions, that make me feel uneasy. And yet others are just a little limited in what they can actually do (basically just symlink a file). I still prefer dewi over everything I have looked at in any sort of detail.

Earlier, I mentioned some mistakes in dewi's design. Let's take a look at some of them: First, I should have never depended on ‘make’: Dewi only used it to call the dewi script (from .dewi/bin) and because the "make deploy" looks pretty. But there's no feature in make that the basic dewi features actually need. And then you just end up with a bunch of downsides, like:

  • Superfluous dependency, that a target system has to satisfy
  • Proper portable make code is actually not that easy, and I always get issues on OpenBSD systems for example.
  • Using make required a Makefile in each dewified sub-directories to exist. Which means that you pollute the sub-directory's version control history with changes to that file each time dewi updates it.
  • If someone wants to use make as part of their deployment system, they can use it on top of a make-less dewi-system at will.
  • Needlessly complicates the whole system.

You can think of more. It was just wrong to use ‘make’.

And the second major mis-design was the case of keeping the code for dewi in the dot-dewi sub-directory. The idea was to ensure, that the deployment process doesn't ever break due to changes in dewi that might be in updated system version. That's still a moot point however, since nobody keeps someone from installing a fixed version of dewi into ‘~/bin’ and never ever change it. Dewi can be used from its source directory as well and its non-standard dependencies (dewi's implementation language, Perl, is installed on virtually all systems I have come across) are optional dependencies; no need to install anything. Instead, keeping the script in the ‘.dewi/’ directory made the system much less clear and much more confusing.

These issues are both fixed now. Dewi is now a single command line tool, that ships all its code. And where you previously did this:

% make deploy

…you are now doing this:

% dewi deploy

To discuss all changes in dewi since version 0.2 would completely go beyond the scope of a single blog post. Instead, let me list a few highlights:

  • You can now apply filters when deploying files (useful, if your configuration files carry sensitive information).
  • You can now use multiple input files to deploy into a single destination file.
  • Dewi now lets you run your own code while it works, because it lets you define hooks.
  • Dewi now has better support for deploying large, recursive trees of files.
  • You can now deploy files with full support of templates using Perl's Template module (available from CPAN).

Another thing that may be interesting for a few users is the trivial call of its register() function: That one takes a string argument, that is the name of a source file. Its effect would be to deploy that file using the copy method, after the source file name was turned into a dot-file-name. Copying was the default choice of deployment, because it absolutely works everywhere.

However, sometimes you may want to take changes you do to source files immediately after saving them to disk. You may think “symbolic links!” right now and you would be right. The trivial call style of register() now allows the user to supply string-options. So now the canonical example of a Dewifile for a git-configuration that should be symlinked to its source looks like this:

register '--symlink', 'gitconfig';

For all details, take a look at the CHANGES and UPGRADING files as well as the new and updated manuals dewi(7), dewi(1) and dewifile(5) (see below).

I am planning to release version 1.0 of dewi based on version 0.3 once it had time to settle a little and have remaining bugs fixed, if they come up, and to have its documentation be polished further. I consider dewi to be pretty feature complete right now, which is why after 1.0 it'll go to maintenance mode.

Thanks for listening. ☺

Related links:

Posted Fri 29 Jul 2016 01:31:03 CEST Tags:

You may have seen this already, but I thought I'd mention it anyway, because I like the level of detail some people put into their work. Like with this list of easter eggs that made it into episode one of season two of Mr.Robot. Once you make it the the website with the in-browser operating system with a working window manager, a small working shell and a cute impression of an IRC client, you may agree.

Posted Sun 17 Jul 2016 12:04:28 CEST Tags:

If you're using git with zsh, you may have seen this:

% git show HEAD^1
zsh: no matches found: HEAD^1

…and wondered what in the name of all that is holy is going on.

The reason behind this is, that zsh signals an error if you provide it with a pattern, that doesn't match any files. This is the sane thing to do. Especially in interactive shells. If your shell behaves differently, I am sorry.

Your reaction might be “What pattern are you speaking of?” — since there is no asterisk, question mark or similar construct in there. That is true, but zsh has pretty powerful extended patterns, if enabled. They let you to pull off lots of things you might resort to regular expressions for, in certain situations. Characters like “#”, “~” and “^” become special characters and must be quoted if their special meaning is to be suppressed.

So that is what's going on. And sometimes git users get annoyed.

With git, though, you almost never want your shell to do any globbing anyway. Seriously. On the one hand, that is because git more often than not interacts with its database rather than with files, so files don't come into play to start with. And on the other hand, even when you pass stuff to git that looks like a file pattern, often you want git to expand the pattern itself. Like with “git grep”:

% git grep 'foo.*bar' -- '*.h'

This finds all lines that match the regular expression “foo.*bar” in all files that match the pattern “*.h”. No matter in which subdirectory the header file is hidden in.

Git is really one of the most eligible commands to have globbing (the expansion of patterns in file names) turned off for. And zsh let's you do that:

alias git='noglob git'

Now when you execute commands like these:

% git show HEAD^1
% git grep foo.*bar -- *.h

…zsh will not expand any patterns for list of files and instead hands all arguments over to git unchanged. Which is exactly what you want almost every time.

In the odd case, when you really do want the shell to do globbing, you can circumvent your shell from using the alias you just defined: In case you've got the EQUALS option set (which is the default) you can do:

% =git add *.txt

Try “echo =git” to see why that works.

If you don't use that particular option, you can always turn off alias expansion temporarily by prefixing the alias name with a backslash:

% \git add *.txt

And that's that.

Posted Mon 20 Jun 2016 21:55:38 CEST Tags:

The previously commercial Scheme implementation (for more than 30 years) known as Chez Scheme from Cadence Research Systems (which was aquired by Cisco in 2012) was released as Open Source software using the Apache Licence 2.0.

This is a pretty cool move by R. Kent Dybvig and Cisco making this high quality implementation available to the general public. Chez has, among other things, support for compiling Scheme sources to native machine code. Something that my go-to Scheme GNU Guile doesn't feature (although there are long term plans into that direction, as far as I know).

In case you're interested:

Posted Sun 01 May 2016 00:37:40 CEST Tags:

Der OpenSourcePress Verlag hat scheinbar die Ohren angelegt.

In diesem Verlag ist das deutsche Buch zu Git erschienen. Die Verlagsrechte sind nun wohl an die Autoren zurück gegangen und die haben sich entschieden ihren kompletten Krempel unter CC-NC-SA Lizenz zu veröffentlichen. QuellenHTML Version des Buchs

Posted Sun 03 Jan 2016 12:24:38 CET Tags:

As it turns out “Christmas” is really this Christmas. I'm talking about Perl 6 of course.

Perl was the third programming language I learned (tied with C, which I started out with around the same time) and the first language I was comfortable using (before I was using Basic and Pascal, both of which I found rather lacking).

Perl is not a perfect language, not by a long shot — although, most of the criticism (especially the harsh ones) I hear comes from people who never really read or wrote any non-trivial Perl code. But since people on the internet said so, it's reasonable to blabber along. But since the default language behaviour (no "use strict" and no "use English") allows and invites — how do I put this — interesting code, even fans of the language cannot deny that. I have written some aweful stuff myself. I wouldn't want to work on my old programs. Not even for lots of money. Nobody is forced to write ugly ass code in Perl, though. And there are some beautiful examples out there.

However, this blog post is not about the Perl of old. No sir. This is about a language, that a number of smart people started to design in 2000: Perl 6 — A new incarnation of the Perl language:

For the first time, there would be a specification of the language. For the first time it would be clear how to parse Perl (with Perl5 the saying goes "Only Perl can parse Perl. And the tokenizer is black magic."). Perl6 is its own language in the tradition of previous Perls, but much more consistent and with less obscure defaults. “More Awesome. Less Crazy.” if you will.

Perl6 was also thought of as vaporware, as in "Nice idea, that is never going to happen". With respect to its release date, the designers used to say "We'll release on Christmas. We just don't know which Christmas it is going to be."

And like I said above, as it turns out, it's this Christmas. 15 years of development has not been four naught. Just browse Rosetta Code for some Perl6 examples. You'll notice the heavy use of operators in Perl6, of which I'm sure the askell fans will be fond of (Haskell is one Perl6's major influences anyway); also with Unicode characters like the MD5 implementation on Rosetta Code shows. You might also like how Perl 6 handles parallelism, asynchrony and concurrency

Don't give in to prejudices: Take a look at the examples on the Perl 6 homepage or Rosetta Code. Browse the Advent Calendars. Some of the features are amazing and if the community can grow into a decent size, so that the number of libraries grow into a useful lot, Perl 6 could be an amazing world to work in.

Posted Sat 26 Dec 2015 12:51:19 CET Tags: