Portable Emacs Eshell Aliases

I maintain one emacs config file (.emacs) for all environments and systems whereever I use emacs. From time to time I use eShell but aliases were differing from system to system. The reason was, that they were stored in a separate file (~/.emacs.d/eshell/aliases) which I do not re-distribute.

So, my solution was to maintain eshell aliases inside my .emacs file. Here are my current alias definitions:

;; actual aliases
(+alias 'l      '(ls -laF))
(+alias 'll     '(ls -l))
(+alias 'la     '(ls -a))
(+alias 'lt     '(ls -ltr $*))
(+alias '..     '(cd ..))
(+alias '...    '(cd ../..))
(+alias '....   '(cd ../../..))
(+alias '.....  '(cd ../../../..))
(+alias 'md     '(mkdir -p))
(+alias 'emacs  '(find-file $1))
(+alias 'less   '(find-file-read-only $1))

As you can see, I use a pretty handy function +alias to create them and I use symbols, not strings which looks cleaner. For this to work, I use the following function:

(setq eshell-command-aliases-list ())

(defun +alias (al cmd)
  "handy wrapper function to convert alias symbols to alias
strings to avoid writing 4 quotes per alias. AL is a single-word
symbol naming the alias, CMD is a list symbol describing the
(add-to-list 'eshell-command-aliases-list (list (symbol-name al) (mapconcat 'symbol-name cmd " "))))

So, first the aliases list will be cleared, just in case there's some aliases file left in the filesystem (which I ignore from now on). The function +alias then converts the given symbols to strings and adds them to the alias list.

I could of course use strings directly but that's too much quotes to type and looks confusing. Just for completeness, here's how the aliases list looks like after the above conversion:

(("less" "find-file-read-only-other-window $1")
 ("emacs" "find-file-other-window $1")
 ("md" "mkdir -p")
 ("....." "cd ../../../..")
 ("...." "cd ../../..")
 ("..." "cd ../..")
 (".." "cd ..")
 ("lt" "ls -ltr $*")
 ("la" "ls -a")
 ("ll" "ls -l")
 ("l" "ls -laF"))

13.03.2017 19:32 CC0 emacs Emacs

Emacs: comfortable macro recording

A couple of weeks ago I discovered elmacro mode, which is exactly what I was searching for: it turns unreadable recorded emacs macros into editable emacs lisp code. I LOVE it.

However, both the default emacs macro interface as well as the elmacro interface were not comfortable enough to me. So, I came up with this rather long solution for my macro management:

If I want to record a macro, I press F6. Then I do whatever I'd like to record and when I'm done, I press F6 again. That's it. The code below takes care of all the horrible details: while recording a macro a red indicator will be shown in my mode line. The macro will be saved to disk. Another function with the same name with -repeat appended will be saved as well. Both will be evaluated so that I can use them immediately. The -repeat version allows me to run the macro repeatedly with an interactive menu. When I press a it will be repeated til EOF, when I press ENTER it will be executed once (which can be repeated, hence the name), when I press e I can enter another macro name (with completion) and when I press q the menu will be quit. The same function will be called when I press CTRL-F6, it will present the mentioned menu, so that I can also just execute the last recorded macro.

;; always enable emacro mode
(require 'elmacro) (elmacro-mode) ;; var must be global so it can be shared across functions
(setq my-macro-name "last-macro") ;; ignore some certain events
(add-to-list 'elmacro-unwanted-commands-regexps "^(mouse.*)$") (add-to-list 'elmacro-unwanted-commands-regexps "^(my-start-or-stop-macro)$") ;; called when saving a macro
(defun my-get-macro-name() "Ask for a macro name, check for duplicates. If the given name is already
defined, ask again (and again until unique). If a buffer with the given name
exists, kill it (that is, the buffer is there but has not been saved or evaluated
yet). Return the name as string."
(interactive) (let ((done nil) (name nil) (mbuf nil) (err "")) (while (not done) (setq name (read-string (format "%s - enter macro name (last-macro): " err) nil nil "last-macro")) (if (fboundp (intern name)) (setq err (format "macro '%s is already defined" name)) (setq mbuf (format "* elmacro - %s *" name)) (if (get-buffer mbuf) (with-current-buffer mbuf (kill-buffer mbuf))) (setq done t))) name)) ;; interactive macro prompt with completion
(defun my-get-exec-macro-name() "Ask for a macro name to be executed" (interactive) (let ((macros ()) (N 1) (S nil) (T "")) (dolist (entry (cdr (assoc my-macro-file load-history ))) (setq S (cdr entry)) (setq T (symbol-name S)) (push (list T N) macros) (setq N (1+ N))) (completing-read "enter macro name: " macros nil t nil))) ;; the heart of my elmacro stuff: starts macro recording or
;; stops it if emacs is already recording. This way I can
use 1 keybinding for start+stop
(defun my-start-or-stop-macro() "start macro or stop if started" (interactive) (if (eq defining-kbd-macro nil) (progn (elmacro-clear-command-history) (start-kbd-macro nil) (message "Recording macro. Finish with <shift-F6> ...")) (progn (call-interactively 'end-kbd-macro) (setq my-macro-name (my-get-macro-name)) (elmacro-show-last-macro my-macro-name) (message "Recording done. Execute with <C-F6>, save or <C-x C-e> buffer...")))) ;; better than the default function
(defun my-exec-last-macro(&optional ARG) "execute last macro (or ARG, if given) repeatedly after every <ret>, abort with
C-g or q, and repeat until EOF after pressing a. If macro defun is known
(i.e. because you evaluated the elmacro buffer containing the generated
defun), it will be executed. Otherwise the last kbd-macro will be executed."
(interactive) (let ((melm-count 0) (melm-all nil) (melm-abort nil) (melm-beg (eobp)) (melm-code (or ARG my-macro-name)))
 (if (eobp)
(if (yes-or-no-p "(point) is at end of buffer. Jump to top?") (goto-char (point-min)))) (while (and (not melm-abort) (not (eobp))) (when (not melm-all) (message (concat (format "Executing last macro '%s (%d). Keys:\n" melm-code melm-count) "<enter> repeat once\n" "a repeat until EOF\n" "e enter macro name to execute\n" "<C-g> or q abort ..\n ")) (setq K (read-event)) (cond ((or (eq K 'return) (eq K 'C-f6)) t) ((equal (char-to-string K) "q") (setq melm-abort t)) ((equal (char-to-string K) "a") (message "Repeating until EOF")(setq melm-all t)) ((equal (char-to-string K) "e") (setq my-macro-name (my-get-exec-macro-name))) (t (setq melm-abort t)))) (if (not melm-abort) (progn (if (fboundp (intern melm-code)) (call-interactively (intern melm-code)) (call-interactively 'call-last-kbd-macro)) (setq melm-count (1+ melm-count))))) (if (and (eq melm-count 0) (eq (point) (point-max))) (message "(point) is at end of buffer, aborted") (message (format "executed '%s %d times" melm-code melm-count))))) ;; I use my own macro file, my-lisp is defined somewhere else
(setq my-macro-file (concat my-lisp "/macros.el")) ;; load if it exists
(if (file-exists-p my-macro-file) (load-file my-macro-file)) ;; store the macro defun generated by elmacro-mode to disk
(defun my-macro-store() "store current macro to emacs config" (interactive) (copy-region-as-kill (point-min) (point-max)) (if (not (get-buffer "macros.el")) (find-file my-macro-file)) (with-current-buffer "macros.el" (goto-char (point-max)) (newline) (insert ";;") (newline) (insert (format ";; elmacro added on %s" (current-time-string))) (newline) (yank) (newline) (save-buffer)) (switch-to-buffer nil) (delete-window)) ;; add a repeating variant of the generated function,
;; evaluate and store both of them to disk
(defun my-macro-gen-repeater-and-save() "generate repeater and save the defun's Runs when (point)
is at 0,0 of generated defun."
(next-line) (goto-char (point-max)) (newline) (insert (format "(defun %s-repeat()\n" my-macro-name)) (insert " (interactive)\n") (insert (format " (my-exec-last-macro \"%s\"))\n" my-macro-name)) (newline) (eval-buffer) (my-macro-store)) ;; so, always evaluate generated macro code, store it to disk and
;; close the temp buffer
(advice-add 'elmacro-show-defun :after '(lambda (&rest args) (my-macro-gen-repeater-and-save))) ;; workflow: shift-F6 ... do things ... shift-F6, enter a name, new
;; buffer with macro defun appears. C-x C-e evals it. C-F6 (repeatedly)
;; executes it.
(global-set-key (kbd "<f6>") 'my-start-or-stop-macro) (global-set-key (kbd "<C-f6>") 'my-exec-last-macro) ;; face used to indicate ongoing macro recording on the mode line
(defface rec-face '((t (:background "red" :foreground "white" :weight bold))) "Flag macro recording in mode-line" :group 'my-mode-line-faces) ;; custom modeline including recording marker
(setq-default mode-line-format (list "%e" mode-line-front-space mode-line-mule-info mode-line-modified mode-line-remote " " mode-line-buffer-identification " " mode-line-position " (%m) " '(:eval (propertize (if (eq defining-kbd-macro t) "[REC]") 'face 'rec-face)) mode-line-end-spaces))

06.03.2017 22:48 CC0 emacs Emacs

Perl Moo Throwable Example

While working on a project with Moo (the first time for me) I discovered Try::Tiny. It's a great little helper and I highly recommend it. However, on my quest to make better error handling in Perl I thought it would be a good idea to have some kind of exception system.

Turns out, this already exists. In fact it is quite simple: die() accepts a reference as parameter, which could very well be an object. A couple of modules on CPAN make use of this, one of the simplest with the fewest dependencies is Throwable.

Since I could not find a good example of how to use it correctly (which I understood), I'm going to post such an example here for anyone who might be interested.

So, you need to have Moo and Throwable installed first. I'm doing these kind of experiments with perbrew, which I recommend as well! Here's my "Exception" class. It's a Moo role with two attributes (type and msg) and a class method e().

package Ex;
use Moo;
with 'Throwable';

has type => (is=>'ro');
has msg  => (is=>'ro');

sub e {
  if (ref($_) eq 'Ex') {
    return $_;
  } else {
    chomp; return Ex->new(msg => $_, type=>0);

This Exception class will act as our wrapper to throw exceptions or convert old school perl die()'s into exceptions.

Here is a simple Moo class without any attributes which implements two methods X::Nix::tu() and X::Nix::ta(). Both of them just die. The method tu() throws an exception of type Ex - our exception class from above comes into use here. The ta() method on the other hand just dies with a good old croak() call.

package X::Nix;
use Carp;
use Ex;
use Moo; sub tu { Ex->throw({type => 1, msg => 'dont die while root'}); } sub ta { croak "death by disruptor"; }

Now let's take a look at our main script, which uses the X::Nix class and tries to catch both exceptions:

package main;
use Try::Tiny;
use X::Nix;

my $x = X::Nix->new();

try {
} catch {
  printf "died with %d and said: <%s>\n",
    Ex::e->type, Ex::e->msg;

try {
} catch {
  printf "died with %d and said: <%s>\n",
    Ex::e->type, Ex::e->msg;

It calls both methods and tries to catch them. Note how it calls Ex::e->type, though: Try::Tiny puts the exception object/message into $_. The class method Ex::e() uses $_ directly, therefore we are able to leave it in our catch{} code. This is the same thing as Ex::e($_)->type. Here's the output:

died with 1 and said: <dont die while root>
died with 0 and said: <death by disruptor at role.pl line 49.>

So, as you can see, with the help of our Ex::e() class method we can handle real exceptions and old school die()'s the same way, wo don't need to distinguish between the two. This way you can use foreign perl modules which use croak() and die() and catch those errors as if they were exceptions.

22.11.2016 21:28 CC0 opensource perl Source

Komische Wolken über Fehmarn

Hab ich noch nie gesehen, Streifen quer über den ganzen Himmel:

Bild: Streifen Panorama 1
Streifen Panorama 1 (Sept. 27, 2016, 7:50 p.m.)
[Tags: foto ] [Album: Natur ]
Bild: Streifen Panorama 2
Streifen Panorama 2 (Sept. 27, 2016, 7:50 p.m.)
[Tags: foto ] [Album: Natur ]

27.09.2016 19:50 CC0 Draussengewesen

Sendgrid, Mailgun et all: SPAM providers - Updated 02.10.2016 10:49

Last month I got an email from OTTO.de asking me to attend a survey about customer satisfaction and the like. Bad for them: I use mutt and therefore it is obvious if an email is fake. So, what did OTTO.de do? They gave my email address (and I suspect those of all other customers) to an external "reasearch" company. This company then sent the email using the mail service of another company. All of this happened without my consent.

Now, the good news is, that OTTO.de responded quickly to my complaint and ordered both companies to delete my email address, however I cannot be sure if they actually DID delete it though. The other good news is that I create always an email address for every shop, forum or any other login site I use. That way, I can just drop "burned" email addresses and stop using the single service for which I created it.

But most peope do not operate their own mail server and create an alias for every site they use. For such peope a "burned" email address is a disaster. By "burned" I mean the email address is out of your control, you don't know who's using it anymore, you start to receive SPAM to this address. But if this is the only email address you possess and if you use it for everything, you're fucked. Changing an all-purpose email address, deposited on dozens or even hundreds of sites, is a nightmare.

I have this problem at work. One of our vendors, an israeli company, sends us notifications by email. At work I only have one email
address, it's associated with my name and I cannot change it. The israeli company sends those notifications by using the services of a company called Sendgrid. Now, sendgrid not only knows my name, my location, my employer, they also know what kind of job I have and that our company uses the services of this israeli company.

I never allowed them to do this. And I cannot change this, it already happened. My work email address is burned and I have to continue using it. This is more than annoying.

Much more annoying is the fact, that people using such services don't even think about it. I complained with the israeli company and they did not understand my problem at all. It was as if I am from mars trying to communicate with people from venus. They even nonchalantly closed the case.

What I tried to say to them was that Sendgrid is a SPAM sending service. And it is a US company, operating in a country with almost no privacy protection laws. They didn't get it. I suspect, young people don't even understand what SPAM is these days, I don't know.

The other day I stumbled upon the story about the operatos of vDOS, a DDoS service. It was a criminal enterprise and they used a mail sending service as well: Mailgun. Mailgun does the same as Sendgrid. It's a SPAM sender company. In order to understand the
nature of their business, look at the numbers:

Sending 5.000.000 emails costs 0.00015 Dollars.

How do they make profit, you ask? Well, look at this, which can be found in a job description:

We have a passion for solving hard problems – our services are
responsible for processing billions of messages each month and have to
not only scale, but be highly reliable.

I don't know who else needs to send such impossible amounts of emails than SPAMmers. And if all of their customers operate like OTTO.de or the mentioned israeli company, almost nobody agreed to this.

An email you receive from a sender you don't know, you don't have any relationship with, you don't do business with - is SPAM. Period.

The only difference to past times is that operating an email sending venture was an illegal operation while today it is perfectly okay for all parties, including their victims.

I've got to admit they are clearly geniuses. Converting a foul smelling "business" into something you get venture capital for, create APIs, get praised by managers AND developers is a coup I need to salute for.

But how much all those hipsters, ruby-on-rail-loosers and java-scriptsters love services like Mailgun or Sendgrid: what they do stinks, it violates peoples privacy without asking (and I didn't even talk about their tracing features!) and in the end burns peoples 
productive email addresses.

I can't even imagine how such a company can be a legal business. This is incomprehensible.

Update 16.09.2016 18:24:

Here's another example:

Received: from mailer212.agnitas.de (mailer212.agnitas.de [])
From: voelkner - direkt günstiger  
Agnitas.de, yet another SPAM sending venture, sends mails in the name of Voelkner (also known as fake mails) to me. So, Voelkner gave them my email address without my consent.

What the fuck?!

Update 02.10.2016 10:49:

And yet another one:

Received: from m69-130.mailgun.net (m69-130.mailgun.net [])
From: noreply@shop.drak.de
This time, DRAK an aquaristic vendor, uses Mailgun, to send unsolicited SPAM mails to me In this case as well I didn't give my consent. In the case of DRAK, even their TOS claims that they'd not do such things (that is, give customer data to a third party without consent).

11.09.2016 11:52 CC0 Unfassbar

Hamburger Buns

Ich habe gestern diese Hamburger Brioche Buns hergestellt. Zur Abwechslung habe ich mich präzise an das Rezept gehalten, keine anderen Mehlsorten, kein LM usw. Einzige Änderung: Teig nach Bertinet bearbeitet und nicht geknetet. Und was soll ich sagen: Die Brötchen waren der Hammer und die Hamburger sensationell.

Wir haben gefressen. Alter war das geil.


Bild: Die Brötchen. Guck Dir das mal an!
Die Brötchen. Guck Dir das mal an! (Sept. 4, 2016, 11:56 a.m.)
[Tags: backen ] [Album: Backdat ]
Bild: Wie vorhergesagt erfüllen die Brötchen alle Anforderungen an ein Hamburgerbrötchen. Top! Übrigens erkennt man an der nicht ganz so regelmäßigen Porung die andere Teigbearbeitungsmethode.
Wie vorhergesagt erfüllen die Brötchen alle Anforderungen an ein Hamburgerbrötchen. Top! Übrigens erkennt man an der nicht ganz so regelmäßigen Porung die andere Teigbearbeitungsmethode. (Sept. 4, 2016, 11:56 a.m.)
[Tags: backen ] [Album: Backdat ]
Bild: Profi-Patties: Rindsgulasch fein, Rinderfilet und Entrecote grob, 2 Finger dick Schweineschwarte, Salz, Pfeffer, bischen Semmel mit Milch, wenig Ei: Boah ey!
Profi-Patties: Rindsgulasch fein, Rinderfilet und Entrecote grob, 2 Finger dick Schweineschwarte, Salz, Pfeffer, bischen Semmel mit Milch, wenig Ei: Boah ey! (Sept. 4, 2016, 11:56 a.m.)
[Tags: backen ] [Album: Backdat ]
Bild: Sowas von!
Sowas von! (Sept. 4, 2016, 11:56 a.m.)
[Tags: backen ] [Album: Backdat ]

04.09.2016 11:53 CC0 backen Kochen


Das erste Mal im Leben hab ich Marmelade gemacht: Pflaumenmuß und Holundermarmelade.  Mit Rezepten aus dem 19ten Jahrhundert. Und die Sachen sind wirklich lecker. Nur ein bischen viel ist es geworden.


Bild: Pflaumen in rauen Mengen
Pflaumen in rauen Mengen (Aug. 28, 2016, 12:40 p.m.)
[Tags: ] [Album: ]
Bild: 38 Gläser Pflaumenmuß, haha!
38 Gläser Pflaumenmuß, haha! (Aug. 28, 2016, 12:40 p.m.)
[Tags: ] [Album: ]
Bild: Ein bischen Kompott ging auch noch
Ein bischen Kompott ging auch noch (Aug. 28, 2016, 12:40 p.m.)
[Tags: ] [Album: ]
Bild: Holunderbeeren: 4 Stunden Arbeit für diese Schüssel
Holunderbeeren: 4 Stunden Arbeit für diese Schüssel (Aug. 28, 2016, 12:40 p.m.)
[Tags: ] [Album: ]
Bild: Aber: 18 Gläser Marmelade waren es wert
Aber: 18 Gläser Marmelade waren es wert (Aug. 28, 2016, 12:40 p.m.)
[Tags: ] [Album: ]

28.08.2016 12:31 CC0 kueche Kochen

Fahrradtour am Main

Ich war mal wieder in Frankfurt und habe mir diesmal die Zeit mit einer schönen Fahrradtour vertrieben:


25.08.2016 22:36 CC0 foto natur Draussengewesen

How to backdoor store-and-forward public key crypto?

So, the german and french government want to break cryptography. Now they "only" want to be able to decrypt messaging apps. If they get their law - and since there's not much sanity left in the corrupt EU this will likely happen - what will be next?

I think store and forward crypto systems are the first to come into mind, that is: PGP. Happily I am the maintainer of some nice but working play store and forward crypto software: PCP. Of course it is not PGP but uses comparable features. So, after reading the news the other day I thought to myself:

How would I implement such a backdoor in PCP, if I had to?

As it turned out the answer is hillariously simple! PCP, as GNUPG, supports encrypting data for multiple recipients. Therefore the task is easy: create a "government key pair", hardcode its public key into the encryption code and encrypt everything for this recipient as well.

Here's the backdoor patch.

The patch includes the "government's" secret key. Here's how to use it:

  1. Compile the patched pcp source as usual, install the binary as pcp1-backdoored or something like that.
  2. Create a test user on your system, say "spook".
  3. As user "spook" import said secret key, the import passphrase is "gov".
  4. As another user on the same system export your public key.
  5. Import that key as user "spook".
  6. Now as the regular user, encrypt some file asymmetrically for someone else (e.g. import one of the public key files in the tests/ directory of the source code) using the backdoored binary.
  7. As user "spook" decrypt the encrypted file as if you'd be the intended recipient.
  8. Et voilá.


[24.Aug 17:09:05] --- [~] ---
tom@vm: % src/pcp1 -V spiedsender.vault -l
Key ID               Type             Creation Time        Owner
0x5C77C305F0BF8333   primary secret   2016-08-24T15:13:02  Freddy Victim <victim@gmail.foo>
0x616BDDA58845987B   valid public     2015-04-17T17:08:19  Bobby <bobby@local>

[24.Aug 17:15:29] --- [~] ---
tom@vm: % src/pcp1 -V backdoor.vault -l
Key ID               Type             Creation Time        Owner
0xF93E7016447D28CC   primary secret   2016-08-24T14:54:28  The Government <spooks@the.gov>
0x5C77C305F0BF8333   valid public     2016-08-24T15:13:02  Freddy Victim <victim@gmail.foo>

[24.Aug 17:15:43] --- [~] ---
tom@vm: % echo "for bobbys eyes only" | src/pcp1 -V spiedsender.vault -i 0x616BDDA58845987B -e -O encrypted-for-bobby.asc
Enter passphrase to decrypt your secret key: 
Encrypted 242 bytes for:
  0x616BDDA58845987B - Bobby <bobby@local>

[24.Aug 17:16:14] --- [~] ---
tom@vm: % src/pcp1 -V backdoor.vault -I encrypted-for-bobby.asc -d
Enter passphrase to decrypt your secret key: 
for bobbys eyes only
Decrypted 21 bytes successfully

There you go. Freddy Victim encrypted some message for Bobby, but the "government" could read it anyway, it only had to import Bobby's public key (which is the difference to PGP, but it's public and much easier to retrieve).

Also note that the "government" just uses regular PCP features, it doesn't even need to use a patched binary, the vanilla one would do. That's because the backdoor is not really a cryptographic backdoor (which is, as many cryptographers already said, impossible). Instead it just adds another recipient. The result looks pretty normal to the uninitiated, just some encrypted file decryptable by two recipients instead only one.

So, as you can see, it couldn't be easier to implement this backdoor. I could even commit this code to Github and I'm pretty sure, no one would take notice (and of course in that case I'd obfuscate it a little to disguise a casual reader). Also, the government could distribute the patched binary. That'd be pretty easy as well, since almost all Open Source systems use binary packaging.

Finally, one question remains though:

How could I determine of an encrypted file has a "hidden" recipient?

I'm not sure. In the case of PCP, I added a debug print statement to the decryption code (git commit) which tells the number of recipients during decryption if -v have been supplied on the command line. Maybe GPG already includes such a function. But of course this could be easily patched away by a backdoored version. So to check if an encrypted file contains more recipients than expected you'd need to check out the source code, compile it manually and then do the checks.

Yes, evil and scary stuff. But as the README of PCP says loud and clearly: Do not use PCP for anything productive or important. However, for real live public key crypto systems the scheme to add a government recipient to all encrypted data could be a realistic possiblity.


24.08.2016 18:48 CC0 crypto opensource pcp Source

Response to Kyle Keen's "Maintainers Matter"

This is a response to the article "Maintainers Matter" by Kyle Keen, which I'm posting here, since his comment system doesn't work for me.

First of all: I agree with you that maintainers are indeed required and do matter - for users of linux distributions. But I think your world view is a little bit too focused on linux distributions:

Supposedly one of Linux's failings is that there is too much pointless choice, too many K and G versions of things and it divides developer efforts. Why have so many window managers and text editors?

This is no failing, this is good. Who is to decide which WM I'm going to use? A maintainer? You? Why? What could I do if my distribution only provides Gnome but I'm a non-mouse-user and NEED xmonad?

Linux is about choice and it's the choice of the users, not the maintainers. That's why we do have so many different distributions: because at some point maintainers went mad, excluded users with their decisions, so the users had to make a fork of the distribution.

Somehow we've gotten this idea that everyone who writes software for Linux does it for the warm fuzzies.

I am writing software. Free software. NOT software for Linux. In fact, I don't care about Linux at all. My software is free, I provide the source, it runs on most unices, including Linux. And besides it is none of your business, what I'm doing it for. Be it for the lulz, for the "warm fuzzies" or for money - as long as the software comes with a free license which enables users to use it as they wish, it is free and everything is good.

Oh, and from my point of view there's only the developer (that would be me) and users. As you see, users includes maintainers. There's no difference. I do not handle bug reports differently whether they come from an "end user" or some "ubuntu maintainer". And why should I?

More fundamentally, the maintainer is the primary line of defence and interaction between users and developers. Maintainers shield developers from uninformed users, allowing the devs to write software with less support overhead. Non-bugs are caught and filtered out. Low-quality bugs reported to the distribution's tracker often becomes a good bug when the maintainer reports it upstream.

Maintainers may do whatever they want, I don't care. But they're not a "line of defence" or some shield between me and users. Maintainers are, if any, a proxy or a filter. I don't need a "line of defense" since I don't consider users to be my enemies. And even if I would, then maintainers would be enemies as well. So where's the point?

And what is a "non-bug"? Who decides? What if I want to know about it? What if it is not a bug, but just feedback. Why in the world is this hidden from me?

Without distros the ISV would have to carry the full weight of support.

Oh, look at the young one :) Do you know, there was a time when no "distributions" were around? During that time, developing and supporting free software was no burden nevertheless.

This is why Linux doesn't have spyware, doesn't come with browser toolbars, doesn't bundle limited trials, doesn't nag you to purchase and doesn't pummel you with advertising.

Wrong. It doesn't have spyware because it's not widespread. Oh, my bad, that's wrong too. Of course there's LOTS of spyware for Linux. Every android device has it installed. Ubuntu contains spyware. Sanctioned by a "maintainer" of some kind.

For the sake of argument, let us presume that all ISVs are ethical and hold the interests of the community as their utmost ideal.

Again, that's not the point of free software. I produce free software so you can do with it whatever you want, including modifying or distributing it. I'm not interested in your ethical values, your religion, your gender, your education, your location or even your species.

And it's the same the other way around: none of those things about me is your business.

But there's another major misconception here: "the community" you say. Which one? The community of Arch Linux users? Linux Users? Unix Users? Free Software Users? Software Users? Users? In the reality (to reuse you phrasing) there's no such thing as "the community". There are a bunch of people who use Arch Linux, but this doesn't constitute automatically a community. Most of Arch Linux users are unknown to Arch Linux maintainers. They are NOT part of whatever kind of community you're dreaming of. And this is the case for all kinds of users.

As long as people just use something, whether they pay for it or not, they are just users of this thing. Take Zippo users for example. Even if there's some "Zippo Community" somewhere, I am not part of that community only because I use a Zippo lighter!

I am part of a community if I subscribe to some list, apply for a forum account, post comments or opinions, contribute code, documentation or the like. Everyone else is not part of this. Seeing it this way is communist thinking. Free people decide themselfes if they want to be part of some kind of "movement" - not some maintainer somewhere in the U.S.

Could ISVs possibly make everyone happy? They can't. It is impossible.

As maintainers can't do as well. That's why we have thousands Linux distros, a couple of BSD's, hundreds of editors, hundreds of window managers and possibly billions of different ways to combine and configure them. And that's the idea behind the whole endeavor, isn't it?

So, let them make universal packages. Who cares? I'll continue to manually compile emacs and xmonad myself whatever distro I'm running on.

21.06.2016 19:15 CC0 opensource unix Source