Wie ich einen HNO-Arzt in Wolfsburg suchte und IT-Probleme fand

In diesem Blog-Eintrag will ich meine Erkenntnisse schildern, die ich während meines Tinnitus gesammelt habe.
For the non-german-readers of this blog: This blog post deals with the experiences I made during my tinnitus.

Zur Vorgeschichte

Am Dienstag vor genau zwei Wochen wachte ich im frühen Morgen von einem hohen Fiepen im Ohr auf. Da ich bis dahin noch nie Probleme mit meinen Ohren hatte, wartete ich den Dienstag ab und hoffte auf Besserung. Leider wurde es auch am Mittwoch nicht besser. Ich muss dazu sagen, dass mich z. B. bereits leise Geräusche beim Einschlafen stören. So nehme ich das Entladen von Kondensatoren als extrem nervig wahr. Der Ton in meinem Ohr bzw. Kopf hatte in etwa die gleiche Frequenz. Bevor ich also verrückt werden würde, entschloss ich mich, einen Arzt aufzusuchen.

Die Suche nach einem Hals-Nasen-Ohren-Arzt

Während der Sommerferien im Allgemeinen und der Werksferien von Volkswagen im Speziellen, ist hier in Wolfsburg wenig los. Das trifft auch auf die Besetzung der Arztpraxen zu. Ich versuchte den halben Mittwoch eine Arztpraxis zu erreichen. Highlight war unter anderem, dass ich in vier Arztpraxen von deren Anrufbeantwortern auf die nächste Vertretung verwiesen wurde, von denen die letzte Vertretung nicht erreichbar war. Teilweise waren bei Google die Telefonnummern der Praxen veraltet oder die Öffnungszeiten stimmten nicht. Hier bekam ich dann auch die erste Idee, eine simple Webseite zu entwickeln, auf der die Ärzte ihre Vetretung eintragen können.

Letztendlich erreichte ich dann telefonisch doch noch eine Arztpraxis, in der mir gesagt wurde, dass diese keinen neuen Patienten aufnehmen. Ich solle doch in die Notaufnahme fahren. Die zweite Anforderung für die Webseite war also ein simple Checkbox: “Nimmt neue Patienten auf”.

Verwechslung in der Notaufnahme

Am Donnerstag Vormittag fuhr mich meine Frau in die Notaufnahme. Ich bekam ein Bändchen mit Barcode um das Handgelenk und wurde in die HNO-Abteilung geschickt. Auf dem Weg dahin überlegte ich, dass es eigentlich ganz cool wäre, wenn man mit dem Bändchen sich seinen Weg durch das Klinikum zeigen lassen könnte. Sei es über einen RFID anstelle des Barcodes oder einen RasPi mit Barcode-Leser und Mini-LCD in den Gängen.

Nachdem ich in der HNO-Abteilung ankam, bin ich direkt verwirrt gewesen. Nirgendwo ein Arzt oder Zimmer, wo ich mich hätte anmelden können. Im Wartezimmer wurde mir gesagt, dass irgendwann eine Ärzten vorbeikommt. Dem war auch glücklicherweise so. So ein automatisierter Check-In wäre nett gewesen…

Ich wurde überraschend schnell ins Behandlungszimmer gerufen. Insgesamt war ich bis dahin nur ca. 45 Minuten im Klinikum. Im Behandlungszimmer fragte mich die Ärztin, ob die Ohrschmerzen sehr stark seien. Ich war wieder verwirrt. Das Geräusch war nervig, aber nicht unbedingt schmerzhaft. Wir stellten beide fest, dass es noch einen weiteren Patienten mit meinem Nachnamen gab. Glück für mich: ich durfte im Behandlungszimmer bleiben und sparte somit jede Menge Zeit. Was mich natürlich andererseits schockierte: Was wäre passiert, wenn sie mir ohne weitere Nachfragen Tabletten gegeben hätte, die überhaupt nicht zu meinen Symptomen passten? Mit einer gezogenen Nummer im Wartezimmer und einem Abgleich mit meinem Handgelenkbändchen wäre das alles erst gar nicht passiert.

Hörtest

Mit meiner Krankenakte und meinem Handgelenkbändchen wurde ich zum Hörtest geschickt. Während sich die zuständige Ärztin auf ihre langsame PC-Software wartete und ich sah, wie der Ladeanzeige im LCD des Hörtestgeräts bedrohlich blinkte, irritierte mich der laute PC-Lüfter. Der gesamte Raum war so isoliert, dass man von draußen absolut nichts hörte. Aber dafür brummte der PC. Nervig. Der Hörtest sollte gerade losgehen, als plötzlich der Akku des Hörtestgeräts leer war. Hätte das Ding gepiept, hätte man das wahrscheinlich schon vorher gemerkt.

Der Hörtest verlief ohne nennenswerte Unterbrechungen. Ich drückte den Knopf, wenn mich mal das Brummen des PCs nicht ablenkte. Alles in allem hatte ich wohl ein glückliches Händchen. Mir wurde das Gehör eines jungen Gottes bescheinigt. Ein junger Gott mit Tinnitus oberhalb von 8 kHz.

Rezepte

Ich durfte mit meinem (ausgedruckten) Testergebnis in der Hand wieder runter in die HNO-Abteilung, wartete kurz und wurde herein gerufen. Die behandelnde Ärztin verschrieb mir Tabletten. Ich bekam einen Zettel mit dem Rezept in der Hand und sollte diesen in der Notaufnahme abgeben. Außerdem erfuhr ich, dass mich nun der HNO, bei dem ich als letztes angerufen hatte, aufnehmen musste.

Den Tag im Klinikum beendete ich damit, dass mir in der Notaufnahme der Zettel mit dem Rezept durch ein wirkliches Rezept ersetzt worden war und ich wurde entlassen.

Terminklärung beim HNO

Im Anschluss an den Krankenhausbesuch rief ich die HNO-Praxis an. Leider nur Anrufbeantworter ohne Ansage. Scheinbar war für heute bereits der Arbeitstag zu Ende. Ich rief am nächsten Tag noch einmal früh an, ärgerte mich über eine äußerst schlechte Warteschleifenmusik, wurde als Patient aufgenommen und bekam direkt für den folgenden Montag einen Termin.

An dieser Stelle fragte ich mich, warum so wenig Arztpraxen die Buchung von Terminen über das Internet ermöglichen. Die Dienste sind ja vorhanden. Für mich als Person, die äußerst ungern telefoniert, wäre das ein Segen. Außerdem wären die Arthelferinnen vermutlich deutlich weniger gestresst. Viele der Telefonate drehen sich vermutlich (?) um Terminabsprachen.

Termin beim Arzt

Montag Nachmittag suchte ich die Arztpraxis auf. Wegen schlechterer Beschilderung liefen ich und ein weiterer Patient bis in die 4. Etage – nur um festzustellen, dass die Praxis im Erdgeschoss war (Memo für die Webseite: Etage und Barrierefreiheit muss sich eintragen lassen).

Nach einer sehr kurzen Wartezeit von 10 Minuten war ich an der Reihe. Ich durfte wieder einen Hörtest absolvieren – den ich auch diesmal mit gutem Drückergebnis meisterte. Der Arzt schrieb mich für den Rest der Woche krank.

Eine Woche später

Die “Erlebnisse” während des Tinnitus beschäftigen mich immer noch. Als Softwareentwickler bin ich es gewohnt, Probleme zu identifizieren und Prozesse zu optimieren. Da sich die Ärzte aber keine Sorgen um einen Mangel an Patienten machen müssen, wird es wohl schwer werden, dort etwas zu optimieren. Der Druck und das Ärgernis besteht eher auf Seite des Kunden (Patienten).

An dieser Stelle muss ich auch noch einmal sagen, dass ich mich von den beiden Ärztinnen im Krankenhaus gut und nett behandelt fühlte. Diese mussten alleine (!) beide Abteilungen leiten, da der Rest der Kollegen krank war. Auch der HNO-Arzt und seine Mitarbeiterinnen waren nett und sympathisch. In diesem Sinne: +1 für die Ärzte, -1 für Prozesse und -1 für das Gesundheitssystem.

Integration testing the mail dispatching in Laravel 5.1

When using the Mail facade in Laravel it is not so easy to test the output of the parsed mail template. Like http://stackoverflow.com/questions/31120567/unittesting-laravel-5-mail-using-mock I received the error Method Mockery_0__vendor_Swift_Mailer::getTransport() does not exist on this mock object. I ended up in listening to the mailer.sending event:

    public function testRegistrationMailIsSend_afterSubmittingForm()
    {
        // flag for closure has been called
        $mailerAssertionHasBeenCalled = false;

        // receive every Event::fire method and pass the reference from the outer scope into the closure
        Event::shouldReceive('fire')->andReturnUsing(function($event, $params) use (&$mailerAssertionHasBeenCalled) {
            // filter only the mailer.sending event
            if ($event != 'mailer.sending') {
                return;
            }

            // reference will be modified
            $mailerAssertionHasBeenCalled = true;
            // Swift_Message; Illuminate\Mail\Mailer::sendSwiftMessage
            $msg = $params[0];

            $this->assertEquals('Verify your e-mail account', $msg->getSubject());
            $recipients = $msg->getTo();

            $this->assertTrue(array_key_exists('my@domain.com', $recipients));
            $verificationKey = Registration::first()->verification_key;

            // assert registration key is present in parsed template
            $this->assertContains('/registration/verify-email?key=' . $verificationKey, $msg->getBody());
        });

        // visit our registration controller
        $this->visit('/registration')
            ->submitForm('Register', ['email' => 'my@domain.com'])
            ->see('Mail has been sent');

        // make sure that our closure has been called
        $this->assertTrue($mailerAssertionHasBeenCalled);
    }

Seeding the database for integration tests in Laravel

In my last post I wrote about how to define the test environment for database integration tests. Now I want to describe, how the database can be populated with test or stam data.

First of all, every test inherited from the generated TestCase class executes the Artisan migrate command (TestCase::prepareForTests()). The trait Illuminate\Foundation\Testing\DatabaseMigrations is only required, if all tables of the schema have be dropped after the test execution. This could be necessary for system tests in which the whole schema is populated with test data. For “simple” integration tests using transactions should be sufficient.
One word about the traits DatabaseMigrations and DatabaseTransactions: Both are executed by PHPUnit before every test method. PHPUnit scans all methods in the test class for the documentation annotations @before, @after, @beforeClass and @afterClass (PHPUnit_Framework_TestCase::runBare() and PHPUnit_Util_Test::getHookMethods()). The traits both uses the @before annotation to setup the context:

trait DatabaseMigrations
{
    /**
     * ckl: this annotation advises PHPUnit to run the trait before every test case
     * @before
     */
    public function runDatabaseMigrations()
    {
        $this->artisan('migrate');

        $this->beforeApplicationDestroyed(function () {
            $this->artisan('migrate:rollback');
        });
    }
}

With this in mind the seeding of the database can be placed on two different locations. First of all, the non-working approaches. Putting the seeding inside the setUp() or prepareForTests() method does not work, because at runtime there is no active transaction:

    public function setUp() {
        parent::setUp();
        // ckl: wrong place; this method is called on startup. The seeding is outside an active transaction
        // $this->seed('QualificationsTableSeeder');
    }

    public function prepareForTests() {
        $sut = $this->app->make('\App\Services\ExperienceService');
        // ckl: wrong place; this method is called on startup. The seeding is outside an active transaction
        // $this->seed('QualificationsTableSeeder');
    }

Using a pure seeder method with @before does although not work. ReflectionClass::getMethods(), which is used by PHPUnit, returns at first all “native” / non-traited methods and after that the traited methods:

    /**
     * ckl: local methods have higher precedence than traits, so this method is called *before* the DatabaseTransactions trait has been called
     * @before
     */
    public function seedTables() {
        $this->seed('MyTableSeeder');
        $testInstance = factory('App\User')->create();
    }

By starting a transaction inside the seedTables(), we have the seeding inside a running transaction:

    /**
     * @before
     */
    public function seedTables() {
        // already start the transaction and let DatabaseTransactions only rollback the transaction. This does only work on the first test case
        DB::beginTransaction();
        $this->seed('MyTableSeeder');
    }

The rollback is done by the DatabaseTransactions trait. It is no problem having two DB::beginTransaction() calls and only one rollback. MySQL does not allow nested transactions, so Laravel starts only the transaction on the first DB::beginTransaction() call. Every other invoke only increments a counter.
Laravel only executes the rollback, if all DB::rollBack() methods have been called. The seedTables() has to look like

    /**
     * @before
     */
    public function seedTables()
    {
        DB::beginTransaction();

        $this->beforeApplicationDestroyed(function () {
            $this->app->make('db')->rollBack();
        });

        $this->seed('MyTableSeeder');
    }

A much cleaner solution is to call the seedTables() method inside every test case:

    public function seedTables() {
        $this->seed('MyTableSeeder');
    }

    public function testSeeding() {
        // ckl: transaction has been started
        $this->seedTables();

        $this->assertTrue(true);
    }

Test environments for database integration tests in Laravel 5

As far as I have read, in Laravel 4 you could define your database integration test environment by adding a testing/database.php or .env.testing.php file containing your configuiration. In Laravel 5 both ways does no longer work. To switch your environment you have two options:

  1. Put both configuration definitions (testing, dev/production) inside your config/database.php:
        'connections' => [
    
            'sqlite' => [
                'driver' => 'sqlite',
                'database' => storage_path('database.sqlite'),
                'prefix' => '',
            ],
            'mysql' => [
                'driver' => 'mysql',
                'host' => env('DB_HOST', 'localhost'),
                'database' => env('DB_DATABASE', 'schema'),
                'username' => env('DB_USERNAME', 'root'),
                'password' => env('DB_PASSWORD', 'root'),
                'charset' => 'utf8',
                'collation' => 'utf8_unicode_ci',
                'prefix' => '',
                'strict' => false,
            ],
            'mysql_testing' => [
                'driver' => 'mysql',
                'host' => env('DB_HOST_TEST', 'localhost'),
                'database' => env('DB_DATABASE_TEST', 'schema_test'),
                'username' => env('DB_USERNAME_TEST', 'root'),
                'password' => env('DB_PASSWORD_TEST', 'root'),
                'charset' => 'utf8',
                'collation' => 'utf8_unicode_ci',
                'prefix' => '',
                'strict' => false,
            ],
    

    and store the configuration defaults in your .env file by adding the configuration keys DB_HOST_TEST, DB_DATABASE_TEST and so on. Eventually you must modify your base TestCase::createApplication to use the mysql_testing connection:

        /**
         * Creates the application.
         *
         * @return \Illuminate\Foundation\Application
         */
        public function createApplication()
        {
            putenv('DB_CONNECTION', 'mysql_testing');
    
            $app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
    
            return $app;
        }
    
  2. I prefer the second solution: Copy the .env file to .env.testing, modify the settings and override the default Dotenv file .env by modifying your base TestCase::createApplication:
        public function createApplication()
        {
            $app = require __DIR__.'/../bootstrap/app.php';
            // ckl: use .env.testing in favor of .env; clear separation between configuration values and configuration definition
            $app->loadEnvironmentFrom('.env.testing');
    
            $app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
    
            return $app;
    

Using GitHub forks or local Git repositories with Composer

For two weeks I have been heavily developing a new web application based upon Laravel. Tonight I searched for an easy filtering solution like Zend_Filter so that the request strings are automagically trim’d, lowercased, and so on. Lucky me, the repository https://github.com/rmasters/filter is available with a composer.json but latest commit from 2013 is not compatible with Laravel 5.1. The compatibility fix would be trivial: editing two files in the composer.json and it is done. But how can I use my own fork on GitHub or my local cloned repository?

I learned, that I can add a repository reference to the composer.json of my application:

"repositories": [
		{
			"type": "vcs",
			"url": "http://github.com/schakko/filter"
		}
	],

Additionally, I have to specify my development branch which contains the Laravel 5.1 fix (laravel51):

    "require": {
        "php": ">=5.5.9",
        "laravel/framework": "5.1.*",
        "laracasts/flash": "~1.3",
        "cocur/slugify": "dev-master",
        "rmasters/filter": "dev-laravel51"
    },

It is important that the Git branch is named laravel51 and not dev-laravel51, otherwise you will receive an error like

Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - The requested package rmasters/filter could not be found in any version, there may be a typo in the package name.

Potential causes:
 - A typo in the package name
 - The package is not available in a stable-enough version according to your minimum-stability setting
   see https://groups.google.com/d/topic/composer-dev/_g3ASeIFlrc/discussion for more details.

Read https://getcomposer.org/doc/articles/troubleshooting.md for further common problems.

Another neat feature is that Composer supports local repositories without any problems. During testing I changed my repository to

	"repositories": [
		{
			"type": "vcs",
			"url": "c:/ckl/projects/github/filter"
		}
	],

and had no longer to push my changes to the remote repository. The code has to be committed to local branch, of course.

Using Subselects with CQL in CMDBuilds “filter” type properties

CMDBuild supports the usage of SQL queries inside the “filter” options if the type is a REFERENCE.

Given:

  • A lookup table named “Software Type” [{Code: DBMS}, {Code: App}]
  • A class Application [{Code: MySQL, Type: DBMS}, {Code: PostgreSQL, Type: DBMS}, {Code: Tomcat, Type: App}]; “Type” references the lookup table “Software Type”
  • A class ApplicationRelease [{Code: “MySQL 5.0″, Application: MySQL}, {Code: “PostgreSQL 9.x”, Application “PostgreSQL”}, {Code: “Tomcat 7.0″, Application “Tomcat”}]; “Application” is a foreign key to the Application class.
  • A class DbmsInstance with a reference/foreign key to ApplicationRelease

Target:

  • By adding/modifying a DbmsInstance, only ApplicationReleases shall be shown which are of type “DBMS”.

How to solve this by using a subselect:

from ApplicationRelease where Id (/(
  SELECT "Id" FROM "ApplicationRelease" WHERE "Application" IN 
	(SELECT "Id" FROM "Application" WHERE "Type" = 
		(SELECT "Id" FROM "LookUp" WHERE "Code"='DBMS')
	)
)/)

Please note, that every referenced column must be quoted with double quotes. Every value of WHERE clause must be quoted using single quotes only!
The (/(…)/) construct introduces plain SQL.

Trying to install CMDBuild and receiving an ORMException “ORM_GENERIC_ERROR”

CMDBuild is a free (“free” as in GPL v2) ITIL solution. The installation of the 2.3.1 version has been a pain in the ass. After applying the database information in the setup wizard, I always received an org.cmdbuild.exception.ORMException: ORM_GENERIC_ERROR. CMDBuild stores its log files (cmdbuild.log, cmdbuild_dd_sql.log) in the “logs” folder of Tomcat where I could find the root cause for this issue. Our PostgreSQL instance is installed on a Windows machine and holds two database templates. template0 has UTF-8 default encoding, template1 uses WIN-1252. During the installation of the database schema of CMDBuild, the template1 is used. The WIN-1252 encoding of template1 is not compatible with the used UTF-8 encoding of CMDBuild/Java. I fixed this issue by re-creating the template1 schema with UTF-8:


DROP DATABASE template1;
CREATE DATABASE template1 WITH template = template0 ENCODING = 'UTF8';
UPDATE pg_database SET datistemplate = TRUE WHERE datname = 'template1';

The next time I hit the install button of the wizard, I received another ORM_GENERIC_ERROR. This time the log stated that the plpgsql language was missing for template1. I altered the template1 by issuing a “CREATE LANGUAGE plpgsql”. After that I was able to install CMDBuild.

Unattended installation of Windows Server 2012 R2 in VirtualBox and getting an 0x80042565 error

Today I struggled with a working configuration for an autounattend.xml for 9600.17050.WINBLUE_REFRESH.140317-1640_X64FRE_SERVER_EVAL_DE-DE-IR3_SSS_X64FREE_DE-DE_DV9.ISO (Windows Server 2012 R2, Standard, Standard Core, Datacenter and Datacenter Core). The unattended installation inside VirtualBox always failed with an error 0x80042565 or did not use the partition scheme I had previously provided.

I suppose that the problem occured in the first place because of the disabled UEFI of my VM. The usage of the following DiskConfiguration section installs Win2K12 R2 correctly:

https://gist.github.com/schakko/d5df24a2aab89e5e7ed0

Dell XPS 15, Linux and HiDPI

A few weeks ago I bought a new notebook (Dell XPS 15, 15″, 512 GByte SSD, Core i7) for my after-work work and home usage. First of all: it is an awesome fast piece of hardware. Fedora 21 boots up in 3 seconds, Eclipse (STS) starts up in around 7 seconds. But it has some disadvantages regarding the hardware:

  • Having the laptop on the lap bends the case, randomly not releasing the buttons, see http://en.community.dell.com/support-forums/laptop/f/3518/t/19601453
  • At the beginning backspace and space key felt like already used. I must admit that I am using a mechanical keyboard at work and for my standalone PC at home, so every other rubber keyboard sucks 😉
  • Return key feels slightly too small at the beginning.
  • High pitching noise, probably coming from the touchscreen. Most of the time it occurs during scrolling through long documents and having CPU load. I am not sure why this happens.

Especially the problem with the non-releasable buttons drove me crazy at first because it seemed to occur randomly. After some days working with the notebook I accepted this failure. All in all it seems to be a very nice notebook for a developer like me, but…

… The HiDPI support for Linux software just sucks. Linus Torvald statement made his statement at the end of 2012 but the current state is still bad:

  • Default Chromium package has no support for HiDPI; buttons and menus have the wrong scaling. Firefox does support HiDPI and so I set it as my default browser.
  • Scaling of some GTK input fields (radio buttons, checkbox) is wrong, see https://bugzilla.mozilla.org/show_bug.cgi?id=975919
  • Using a second display (beamer) totally screws up the X server. I can’t  get a higher resolution than 800*600 when cloning both displays. Not sure, why this happens.
  • IntelliJ (including EAP 14), Eclipse (4.4) and Netbeans (8.x) are having wrong scaled icons. See wiki discussion for Eclipse at https://wiki.eclipse.org/Bug_421383_-_Graphics_Scaling_issues_on_high_DPI_displays

For a list of workarounds, the ArchWiki is the first place to look for.

Fixing gratuitous ARP requests

Due to some internal network problems I fired up Wireshark and saw a lot of gratuitous ARP requests/broadcasts. I had never seen the sending MAC or IP before but could assign it to one the ports our switching hardware. The designated port was used for a Citrix XenServer virtualization environment, so at first I suspected a miconfiguration of one of the bonds and some looping ARP packets. This assumption was wrong: I shutted down the server and the ARP requests still came from the physical network interface, so it could only be a problem/configuration of the interface itself.

I googled for “intel gratuitious ARP” and found the answer: the Intel NIC had an IPMI module and was sending announcements but the GUI was disabled.
Fixing the problem was easy. I ssh’ed into to the Citrix XenServer and used the ipmitool to disable the ARP sending mechanism:

modprobe ipmi_devintf; modprobe ipmi_si
ipmitool -d /dev/ipmi0 lan set 1 arp generate off