Azure App Service & Python, Part II

God I hate Microsoft.

TL;DR – use “Basic” and “B1” as your app service SKUs. Anything “below” won’t work and you won’t know why.

So, why I am again angry? Cause I want to deploy an app service, using terraform. Sounds soooooooooo simple, right? Except I fail at the creation of the app service (even without code, yet).


resource "azurerm_app_service_plan" "plan" {
  name                = "pkd-appservices0"
  location            = azurerm_resource_group.rg.location
  resource_group_name =
  kind                = "Linux"
  reserved            = true

  sku {
    tier = "Dynamic"     # WRONG, use at least "Basic"
    size = "Y1"          # WRONG, use at least "B1"
resource "azurerm_app_service" "appservice" {
  name                = random_string.server.result
  location            = azurerm_resource_group.rg.location
  resource_group_name =
  app_service_plan_id =

  site_config {
    scm_type         = "LocalGit"
    linux_fx_version = "PYTHON|3.8"

Now. What happens? Let’s see:

Error creating App Service "wzkytawt" (Resource Group "pkd-it-appservices0"): 
   web.AppsClient#CreateOrUpdate: Failure sending request: StatusCode=0 -- 
   Original Error: autorest/azure: Service returned an error. Status=<nil> <nil>

What? Okay, our app service fails without any indication. By setting “TF_LOG=TRACE” and reading through 100s of lines of code we get this:

Consumption pricing tier cannot be used for regular web apps

What the fuck is a “consumption pricing tier”? Well, turns out MS doesn’t know as well, at least it’s described exactly nowhere. Also, can you get a list of tiers? No! Of course not! Why would you?¬† Stackoverflow to the rescue, again, btw, and no idea where that guy pulled that priceless list from.

So, set things to “F1 | Free” and everything works.

… or not. Now we get this:

There was a conflict.                                              (really?!)

64 Bit worker processes cannot be used for the site as the plan 
does not allow it.                                                 (WTF?)

For more information on pricing and features, please see:                            (oh! a link! NICE)

Formatting and comments by me … . Now, wondering why the fuck a multi-billion-dollar corp can do less than my Raspi (run 64bit code) I head over to said page. And find nothing. There is not a single mention about 64bit, 32bit, or anything helpful. Just … prices.

Assuming the fuckers just want more money I upgrade SKU to “B1 | Basic”, and everything works. (Update: I just saw that this is actually mentioned in the terraform docs ūüôā

This time for real, and I think I might be onto the path of finally understanding everything Microsoft does.

Cloud Infrastructure

Azure App Service & Python, Part I

A.k.a. “you’ve got to be fucking kidding me”. Azure App Service sucks, as basically any part of Azure. What’s surprising this time is that terraform actually contributes to the sucking on this occasion – usually the Hashi folks do a very good job at reducing the annoyance. But maybe they’ve given up, I wouldn’t blame them.

So what happened?

What confused the sh*t out of me the last days is that I see tutorials (all really, really, really bad) that do use Python versions newer than 3.4 (not surprisingly). But, alas, there’s this: the site_config.python_version field of terraform’s azurerm_app_serviceresource. It allows the values “2.7” and “3.4” (a Python version which eol’ed in March ’19).

After a shit ton of googling I found this, though. Turns out, it’s not even the right field to use!! To select the Python runtime you should use linux_fx_version, which nobody, nowhere, ever documented. And naive me just assumed that something with “python” in its name would be the right thing to use. Stupid, I know, we’re talking Azure here …


A more peaceful rant about Java & Camel

I did it. I feel like I survived something, like I am on the path on enlightenment (and it feels like raising the foot for the first step in a yourney which I know to be several AEs long). Anyway, I’m kinda happy.

What did I do? I succeeded to write this Java code using the Apache Camel library (and yes, that’s it – in total):

import org.apache.camel.main.Main;

public final class CamelPusher {

    private CamelPusher() {

    public static void main(String[] args) throws Exception {
        Main camelMain = new Main();


Impresive, huh?

What took me longest was to add the “file:” in the line camelMain.configure().withXmlRoutes("file:*.xml");. Yup, really.

Code-wise, that is. It took me even longer to set this up:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="" 
  xmlns:xsi="" xsi:schemaLocation="">
  <description>The thing that transfers payment files to OC</description>



    <!-- -->



    <!-- -->

    <!-- -->


          <!-- -->
          <!-- fucking maven shit honestly those java assholes suck so badly -->
        <!-- see here: -->
          <execution>            <!-- Run our version calculation script -->


And this, cause maybe I still don’t fully get maven (and with maybe I mean definitely, and yes I know there’s an error in the Makefile, I’m gonna fix it – later):

all: clean build prepare-test test
.PHONY: all

    rm -rf tmp
.PHONY: clean

    mvn package
.PHONY: build

prepare-test: clean
    mkdir -p tmp/from_here tmp/to_here tmp/and_from_here tmp/to_here_as_well
    echo deeply > tmp/from_here/i-want-to-be-moved.txt
    echo deeply > tmp/and_from_here/hashtag-metoo.txt
    cp target/camelocclient-SNAPSHOT.jar tmp/
    cp test-config.xml tmp/
.PHONY: test

    cd tmp; pwd; java -cp . -jar camelocclient-SNAPSHOT.jar
.PHONY: test

run: test
.PHONY: run

.PHONY: _git_dirtycheck
    [[ ! -z "git status -s" ]] || (echo -e "\n\n***** working dir is dirty. *****\n\n" && false)

.PHONY: _major
_major: _git_dirtycheck
    mvn build-helper:parse-version \
        versions:set \
        -DnewVersion=\$${parsedVersion.nextMajorVersion}.0.0 \

.PHONY: _minor
_minor: _git_dirtycheck
    mvn build-helper:parse-version \
        versions:set \
        -DnewVersion=\$${parsedVersion.majorVersion}.\$${parsedVersion.nextMinorVersion}.0 \

.PHONY: _patch
_patch: _git_dirtycheck
    mvn build-helper:parse-version \
        versions:set \
        -DnewVersion=\$${parsedVersion.majorVersion}.\$${parsedVersion.minorVersion}.\$${parsedVersion.nextIncrementalVersion} \

.PHONY: _set_version
_set_version: _git_dirtycheck
    read -p "new version: " VERSION ; \
    mvn build-helper:parse-version \
        versions:set \
        -DnewVersion=$$VERSION \

.PHONY: _snap
_snap: _git_dirtycheck
    mvn build-helper:parse-version \
        versions:set \
        -DnewVersion=\$${parsedVersion.majorVersion}.\$${parsedVersion.minorVersion}.\$${parsedVersion.nextIncrementalVersion}-SNAPSHOT \

.PHONY: _tag
    git commit -am "Version bump"
    mvn build-helper:parse-version exec:exec

.PHONY: _snap_tag
_snap_tag: _snap _tag

.PHONY: _addsnap
    mvn build-helper:parse-version \
        versions:set \
        -DnewVersion=\$${parsedVersion.majorVersion}.\$${parsedVersion.minorVersion}.\$${parsedVersion.incrementalVersion}-SNAPSHOT \

.PHONY: _release
_release: _git_dirtycheck
    mvn build-helper:parse-version \
        versions:set \
        -DnewVersion=\$${parsedVersion.majorVersion}.\$${parsedVersion.minorVersion}.\$${parsedVersion.incrementalVersion} \

.PHONY: major
major: _major _tag build _snap_tag

.PHONY: minor
minor: _minor _tag build _snap_tag

.PHONY: patch
patch: _patch _tag build _snap_tag

.PHONY: addsnap
addsnap: _addsnap

.PHONY: rel
rel: _release _tag build _snap_tag

.PHONY: release
release: rel

.PHONY: set-version
set-version: _set_version _tag build _snap_tag

.PHONY: setver
setver: set-version

So this is it. That abomination took me days to build.

So now I can do “make release“, get a .jar file, and place something like this next to it:

<?xml version="1.0" encoding="UTF-8"?>

<routes xmlns="">
        <from uri="file:from_here"/>
        <to uri="file:to_here"/>
        <from uri="file:and_from_here"/>
        <to uri="file:to_here_as_well"/>

… having a freely configurable, all-purpose, no-nonsense Camel engine to my disposal, which I can then deploy to any host of my liking to do things which are useful. In that case – it’s supposed to transfer files (the “left” side of the system, a couple of deployments) to S3, and then pull them out (the “right” side of it, one deployment) into a folder on a target machine.

This is it, this is all, this is basically the most trivial use case ever invented, and it’s supposed to be replaced with something “real”. Let’s see how long it takes to get there.

Now, am I happy? Yes. Is this … “good”? No. Does it work? Probably (it does with a file server / sftp transfer system).

But the best part is: I kinda, sorta understand a little bit of what I did. And I am starting to think that Camel might actually be awesome, and maven actually useful – once you start understanding the concepts and ecosystem. But that’s just a vague possibility, given that I still don’t ūüėČ .

I published the files here as well.


A big fucking rant about Java

Well, I’m back to writing Java. It was supposed to be simple – an Apache Camel .jar file which just reads the route definitions from a nearby *.XML file in the same directory. So it can be re-used, because we have a couple of dead simple use cases which just require a Camel runtime and no special Java Beans.

Simple, right.

I’m playing Doom Eternal for fun at the moment. And just thinking of this abomination called “maven”, which Java uses to build shit makes me wish for all maven devs to rot in hell eternally. This piece of junk is basically undocumented. Don’t get me wrong, theres tons of written stuff, intros, tutorials, etc. about maven. It’s just after reading all of them you’re still the same code-copy-pasting monkey you were before. Once you hunted down the snippet on Stackoverflow you go on to the next blackbox.

Examples? Sure.

  • Versions in build plugins. Maven complains, but countless examples I found don’t use any version. (A Java illness, it seems all examples have to be incomplete, otherwise it’s no fun for the developer, right?).
  • Complexity. You can configure the versions-maven-plugin to update the version numbers. To ignore alpha / beta / whatever versions you have to write a regex expression in a separate file and import that to the pom.xml. Of course you write the import statement in the configuration section of the plugin. Writing the rules in there? Naaaaah, too easy my friend. Extra file please.
  • Commands. There’s no help. There’s only “plugins”. No starting point, no idea what’s “default” and what the 1, 2, 3 steps are to get your app built. Just a bunch of horseshit you try out until your app is built. Or you think it is. (Or back to Stackoverflow, take the first example that works and go on to the next blackbox …)
  • Reposities. It seems I built my app several times correctly, then I configured some repositories, and suddenly it was built … more correctly. Don’t ask me why.

Let’s continue with Spring. They once were (and probably still are) on the forefront of “modern”, modularized, reusable, enterprise-pattern-enabled, lightweight Java. Problem is, that’s still way too complex for any sane human being.

Examples? Sure.

  • Configuration. I try to use Apache Camel. Seems to be a great product, all is configurable using either Spring DSL or code. Now if you want to do it with Spring, until today I invested days to find out how to read the fucking configuration from that god-damned configuration file. It’s just. Not. Possible. Sure, countless examples on the net, but that leads me to …
  • the documentation. Just some random notes:
    • The examples there are just don’t cut it and come basically without any documentation.
    • All links which sound like they could help lead to a 404 page.
    • “if you want to do X you can ‘easily’ do this using Spring XML” is a sentence I want to burn now, because … well, there’s no example, usually. You’re just being redirected to some Spring page which explains the Spring concepts in epic detail, with no connection whatsoever to the actual problem with the actual fucking library.
    • If they include a code snippet it’s always without any context. So you have the critical 3 lines, but if you want to include them into an actual application, you wonder about imports, namespaces, setup boilerplates, and countless other things every. Single. Time.
    • In summary it seems the docs are there for the pros who want to just quickly look something up they inconveniently forgot cause they already know a shit ton of shit. If you’re new to this? Yeah, go ahead, it’s easy, here’s a link to the Spring concepts.
    • Oh yeah, and it might be it’s just plainly, utterly, horribly wrong. But Java being nothing but enterprise, it’s at lease consistently wrong all the time.

I think I managed to solve the problem just now. Unfortunately this cost me days, and only because of the most brainwashed, brainfucked eco-system I can imagine.

(Disclaimer: I think Java has some really cool parts as well, just right now – I honestly don’t care. At all.)


Loathing RSpec and Puppet

There are words for how much I hate RSpec (especially RSpec-Puppet), but they would be too harsh to write down.

So now that I don’t have to google the same shit over and over again, here’s what you have to do to get basic puppet module testing up and running (replace $MODULE with your module name, of course):


require 'rubygems'
require 'puppetlabs_spec_helper/rake_tasks'


    concat: git://
    # alternate method, for specifying refs
      repo: git://
      ref:  1.0.0
    # do _not_ forget this
    $MODULE: "#{source_dir}"


require 'rubygems'
require 'puppetlabs_spec_helper/module_spec_helper'


# see also
require 'spec_helper'

describe '$MODULE' do
  context 'default' do
    it {
      should contain_file('/etc/haproxy/haproxy.conf')

    # or ...
    it do contain_file('/this/syntax/is/even/more/retarded')

Final note

It’s “rake spec”, not “rake test”. Of course.


Nervige Puppet Fehler

Was geht hier nicht?

class { 'whatever' : 
    do     => 'something', 
    before => Class[ 'something_else' ],
} -> 

class { 'yeah_yeah' : do => 'even_more', }

Na? Niemand? Gut. L√∂sung: “before =>” und “->” mischen sich nicht. Das w√§re nicht so schlimm, w√§re die Fehlermeldung nicht absolut … unzureichend:

err: Could not retrieve catalog from remote server: Error 400 on SERVER: undefined method `<<' for {}:Hash on node bstrap_foreman_v2. ...

Noch sowas dass man nicht mehr vergisst. Gl√ľcklicherweise gibts grafische git logs …


Puppet, Arrays & Iteratoren

Endlich, endlich, endlich kommt in Puppet 3.2 die M√∂glichkeit, Schleifen zu bauen. Dann k√∂nnte ich eventuell folgende Aufgabenstellung ein klein wenig einfacher realisieren (aktuell arbeite ich bis zur endg√ľltigen Umstellung unserer Systeme mit Puppet 2.7):

Fasse alle im Rechner befindlichen Blockdevices der Form “/dev/sd*” – aber au√üer /dev/sda – in einer LVM volume group zusammen.

Das Herausfinden der Blockdevices erledigt ein Fact aus Facter … naja, nicht ganz – ein in Facter 2.0 verf√ľgbarer Fact, den ma aber dankenswerterweise zur√ľckportieren kann. Dieser liefert uns $blockdevices – eine Komma-getrennte Liste der gefundenen devices, allerdings ohne “/dev/”, also nur “sda,sdb,sdc”.

Das hinzuf√ľgen, und dann … ja, was dann? In Ruby kein Thema, aber jetzt m√∂chte ich von “sda,sdb,sdc” zu [“/dev/sda”, “/dev/sdb”, “/dev/sdc”].

Und das geht so:

# next line broken up for readability
$devices_tmp    = inline_template( '
    <%= devs=scope.lookupvar("::blockdevices")
        .select{|f| ! f.include? "sda" }
        .select{|f| f.include? "sd" }
        .collect{|f| "/dev/" + f}.join "," %>' )

# here we split the string back to an array. 
$devices_wanted = split($devices_tmp, ",")

# but it works.
# isn't life shit?
notify { $devices_wanted : }

Sch√∂n ist anders. Falls jemand eine bessere Idee hat – immer her damit …


The year of the … Applications.

Es gibt ein paar Dinge ohne die ich nicht mehr so richtig leben m√∂chte: Text expander, clipboard history, intuitiver Editor (ViM und emacs z√§hlen nicht), und ein paar andere h√§tte ich gerne. Und hier ist des Linux gr√∂√ütes Plus des Linux gr√∂√üter Fluch: Die Flexibilit√§t. Ein paar recht Gnome-lastige Eindr√ľcke:

Text expander: Hier tut AutoKey einen guten Job. Verwendet Python als Skriptsprache f√ľr “fancy stuff”, schon ziemlich gut. Leider f√ľhrt ein fehlerhaftes Skript zu einem Einfrieren der Applikation, weniger praktisch. Au√üerdem werden die Tastaturk√ľrzel nicht nach der Zuweisung aktiv – sondern erst nachdem man in der tabellarischen √úbersicht auf die “Abbr” (Abbreviation) Spalte der richtigen Zeile klickt, denn dann erst “erscheint” der K√ľrzel dort, und dann erst ist er aktiv. Muss wohl ein Bug sein. Dennoch – klar der funktionale Favorit der Liste hier.

Clipboard manager: Gibts. Aber nicht von Gnome, nur “normales” Gtk+ Programm. Nimmt aber bei weitem nicht alle Tastaturkombis an (ich bin z.B. CTRL-√Ė gewohnt, keine Chance). Bedienung: naja. F√ľhrt dazu dass ich ihn nicht nutze, und daher recht angepisst bin.

Chat app: Gnome hat Empathy. Dies kann jedoch kein OTR (off-the-record messaging, Verschl√ľsselung f√ľr Chats). Nicht weiter schlimm, g√§be es nicht ein Ticket aus 2008 und gestartete Open-Source-Bem√ľhungen. Die FAQ dazu trocken: “Man ist der Meinung” dass L√∂sungen wie OTR nicht wirklich zielf√ľhrend sind, da das Protokoll Verschl√ľsselung inh√§rent unterst√ľtzen sollte. Das wolle man dann unterst√ľtzen (also XMPP mit Jingle, nichts anderes). Au√üerdem: Da Empathy auf Telepathy beruht m√ľsste zuerst die Telepathy lib erweitert werden, “wir sind nicht zust√§dig” kommt da r√ľber. Da ich das aus Prinzip m√∂chte nutze ich Pidgin, dessen Integration in Gnome … “ok” ist. Daf√ľr wesentlich sch√∂ner zu bedienen mit einer eigenen Men√ľleiste, und sinnvollen Men√ľs.

Editor. Wir alle kennen Notepad++, ViM und emacs. Meine emacs-Zeiten sind lange vorbei (schade irgendwie, aber so isses halt), daher finde ich die beiden letzteren einfach befremdlich – zu viel mehr als “:wq” in ViM oder CTRL-X CTRL-C in emacs reichts nicht mehr. Daf√ľr ist unter Windows Notepad++ sehr gut f√ľr produktives Arbeiten geeignet. F√ľr Gnome: Gedit. Und das ist vergleichbar mit Notepad. Ohne “++”. Eine vollkommen sinnfreie app. Gl√ľcklicherweise gibts Sublime Text f√ľr Linux (danke, danke, danke!).

Allgemein sind die Ecken sehr, sehr rund:

  • Notifications. Die Gnome-Notifications sind zwar nett, aber das kleine “x” oben rechts reagiert bei mir zumindest immer erst auf den zweiten Klick.
  • Fonts. Warum hat Freetype nicht von vorneherein Ubuntu-Patches installiert? Das ist ein kaum zu beschreibender Unterschied. Nicht legal?
  • Keyboard-Shortcuts: Manchmal konfigurierbar, manchmal nicht, manche per Textdatei, manche GUI. Manchmal kann man sie zuweisen, funktionieren aber nicht. Manchmal ist eine Vorauswahl in Modifier-Keys oder insgesamt in Shortcuts getroffen.
  • Wenn KDE nun mal die bessere Applikation f√ľr etwas hat, dann sieht das aus wie Java Swing unter Windows: Fremd. Genauso umgekehrt.
  • Bookmarks in Nautilus kann man nur durch CTRL-D oder einen Klick auf das “Optionen”-Zahnrad (da?!?) setzen. Nicht per drag-and-drop, und nicht √ľber das rechts-Klick-Men√ľ, was beides ca. 100x intuitiver w√§re.
  • Die Zuweisung von Dateiendungen zu Programmen funktioniert irgendwie … nicht.
  • Den Hauptbildschirm in den Display-Einstellungen festzulegen ist sehr unintuitiv (man ziehe den winzigen schwarzen Balken von einem Monitor auf den anderen – wenn man das wei√ü total einfach, ansonsten eher unintuitiv)

Und demn√§chst muss ich einfach mal einen positiven Post schreiben, schlie√ülich arbeite ich mit dem System, und das auch noch gerne …



Seit heute morgen bin ich bei Congstar, gewechselt von O2 (bzw. discoPlus) weil mir dort die Gespr√§che doch recht h√§ufig abbrachen. Sah immer lustig aus – man schaut aufs Telefon, sieht 5 Balken, dann pl√∂tzlich “Suche”, dann baut er wieder auf, und man bewegt sich dabei keinen Meter. Das fand ich nicht soo spannend, also ging ich zur√ľck zum Altvater D1.

Congstar allerdings gibt sich beste M√ľhe, einen nicht so besonderen ersten Eindruck zu machen. Ich lege die SIM-Karte ein, und bekomme erst mal “SIM gesperrt” angezeigt. Aha. Leider haben die mir keinen PIN geschickt. Ich also auf Verdacht ins online Portal, in dem ich meine PIN tats√§chlich heraussuchen konnte. Eingegeben, ok. Dann bemerke ich das Fehlen eines Betreiberlogos, bzw. einfach jeglicher Betreiberinfos in der Kopfzeile. Dachte mir “das wird schon”, und fuhr zur Arbeit. Dort bekam ich nach ca. 1h gegen 9:45h eine email, ich k√∂nne jetzt meine PIN auf der Congstar-Seite abrufen. Aha. Ja, danke. Ich nehme das zum Anlass und google mal nach Betreiberlogo und Congstar.

Was ich da finde ist wenig √ľberzeugend. Congstar verwendet offenbar fehlerhafte SIM-Karten, und das schon seit 2011, und angeblich ist dieser Zustand seit April 2012 nicht mehr aktuell. Naja. Congstar-Hilfe sagt, aus “technischen Gr√ľnden” sei die Anzeige auf einem iPhone nicht m√∂glich, und die in Foren propagierte L√∂sung ist, sich eine Nano-SIM mit Micro-SIM-Adapter zu besorgen.

Das geht besser.


The year of … the Printer.

Ah, ich bin langsam Рder Post schimmelt schon eine Weile hier vor sich hin, weil ich den Screenshot hochlade. Jetzt isses soweit. Es geht also weiter mit: Drucken. Denn irgendwann lief das System schließlich, und ich kam an den Punkt, an dem ich etwas drucken wollte. Gnome war installiert, Firefox auch, also theoretisch (kenne ich ja vom Mac, da verrichtet CUPS ja auch hervorragende Dienste) einfach die WebGui aufrufen, Drucker auswählen, fertig.

Zuallererst musste ich an Linus denken: root-Passwort-Eingabe f√ľr die Administration von CUPS n√∂tig. Hm. Egal, eingegeben, dann “Add Printer” geklickt, und erst mal erfreut folgendes gesehen:


Hm. Sieht erst mal gut aus, oder? Na, jedenfalls bis man sich die Frage stellt: Welcher der Drucker ist jetzt genau der hier im B√ľro? Nur Typenbezeichnungen, kein Standort, keine IP? Nicht optimal.

Der Einfachheit halber einfach manuell installieren. IP vom Kollegen erfragt, und los. Und stop. Drucker URL eingeben … nur wie? Mit “http://”? Oder “lpd://”? Oder “ipp://”? Und hier dann mit oder ohne “/ipp” am Ende? Ich entschied mich f√ľr “ipp://” ohne “/ipp”. Dann bitte “Make and Model” ausw√§hlen, Brother war nicht in der Liste, Ende.

Aber kein Problem, Brother gibt ja eigens Linux-Treiber raus. Nur nicht auf der “normalen” Brother-Downloads-Seite, die hat nur Mac und Windows-Treiber. Hm. Ich bin faul, also mal die Variante versucht, die fr√ľher mal ging: Zur√ľck, HP Drucker ausgew√§hlt, PCL6, Testseite gedruckt, klappt … nicht. Na gut, w√§re auch nicht sch√∂n gewesen, aber trotzdem.

Nochmal zur√ľck, Drucker gel√∂scht. Dann Google bem√ľht, die “richtige normale” Brother-Homepage f√ľr den Linux-Support gefunden (w√§re unter Support -> Linux gewesen, und nicht Support -> Downloads, aber ehrlich, wer schaut noch den Rest der Seite an wenn er das Bild unten sieht? Ich jedenfalls nicht).

brother-homepageDort gibts f√ľr das von mir gesuchte Modell 5 Treiber zum herunterladen, und zwar folgende:

  • LPR driver (jeweils als rpm + deb)
  • cupswrapper driver (jeweils als rpm + deb)
  • ppd file

Aha. Ich entschied mich f√ľr PPD, ich bin ja CUPS, ne, und nochmal von vorn: Drucker hinzuf√ľgen, manuell, URL diesmal mit “ipp://…/ipp” (also mit “/ipp” am Ende), und siehe da – jetzt kamen auch automatisch Brother-Ger√§te in der Liste (WTF?), wenn auch nicht das Modell hier im B√ľro. Daher runtergeladenes PPD eingebunden, best√§tigt, Testseite gedruckt, fertig.

Nicht so ganz optimal.