How to Encode an SVG for the `src`-Attribute using PHP

As SVGs should preferably not be base64 encoded when setting them on an -tag src-attribute, the suggested alternative is to URL-encode them. The standard PHP urlencode function unfortunately is not suitable for this task, as the resulting value is not interpreted by any browser as a valid SVG image. Instead, the function rawurlencode has to be used. Took me some time to realize. As soon as you get this, you can also take over some other optimizations; maybe get inspired by Taylor Hunts mini-svg-uri to decode some characters manually to improve the overall size. A final function could possibly look like this:

function svgUrlEncode($svgPath)
{
$data = \file_get_contents($svgPath);
$data = \preg_replace('/\v(?:[\v\h]+)/', ' ', $data);
$data = \str_replace('"', "'", $data);
$data = \rawurlencode($data);
// re-decode a few characters understood by browsers to improve compression
$data = \str_replace('%20', ' ', $data);
$data = \str_replace('%3D', '=', $data);
$data = \str_replace('%3A', ':', $data);
$data = \str_replace('%2F', '/', $data);
return $data;
}

Getting started with elastica queries in Symfony

When integrating Elasticsearch with Symfony, there can be a few troubles for newcomers.

The easiest way to achieve integration is by following the setup instructions of the FOSElasticaBundle, in case you have a running Elasticsearch instance already at least. Symfony 3.1 or higher is required for this bundle. When following the setup instructions, there are a few caveats, which differed from what I expected. In the following post, I try to sketch some of the problems respectively solutions.

  • FOSElasticaBundle will not automatically recognize properties of an objectf, even when the serializer and the persistence model is defined. The properties you want to be mapped have to be listed in the configuration file.
  • To map relations such as ManyToOne, ManyToMany or OneToOne, the property gets a subkey “type” with value “nested”, after which the a new “properties” key is necessary followed by the properties of the related Entity
  • To create a development environment separat from the production index, simply set the index_name attribute of the relevant index to a environment-dependent value, such as “app_%kernel.environment%”

When you finally have the configuration set up, you have to run ./bin/console-dev fos:elastica:populate. This will show you errors in the configuration, if you have some, respectively sync your database with the elasticsearch instance.
The next step you will want to take is to use Elasticsearch to search, duh. This can get tricky at first if you are used to SQL search queries, especially as the relevant query classes are not yet as good documented as expected. The best way for me was to combine the knowledge of which classes exist with the elasticsearch documentation itself.

To translate from an SQL query to an Elastica-Query, keep the following in mind:

  • should means OR
  • must means AND
  • mustNot means XOR
  • to wrap these conditions together, use the Elastica\Query\BoolQuery
  • joins can be simulated with the Elastica\Query\Nested
  • to make comparsions with dates or numbers, use Elastica\Query\Range

With this knowledge, a query such as (...) WHERE (post.title LIKE %$search% OR creator.firstName LIKE %$search% OR creator.lastName LIKE %$search%) AND post.start < $date translates to (for example, in a custom search repository class, extends FOS\ElasticaBundle\Repository) :

setQuery($search)->setFields('firstName', 'lastName');
                $creatorQuery->setPath('creator')->setQuery($nameQuery);
          $textQuery->addShould($creatorQuery);
                $titleQuery = new Match('title', $search);
          $textQuery->addShould($titleQuery);
$overallQuery->addMust($textQuery);
          $dateQuery = new Range('start', array('lt' => $date->format(ELASTICA_DATE_FORMAT)));
$overallQuery->addMust($dateQuery);

/** ... **/

This query can be executed like it is on the finder/repository yielding results. But. It will not work with a Paginator and a default number of 10 results will be returned instead. To successfully get the PaginatorAdabter, the whole BoolQuery has to be wrapped in an Elastica\Query Object.
This could be achieved e.g.:

$query = new Query();
// code from above
$query->setQuery($overallQuery);

And to get the Pagination working:

$elasticaFinder->createPaginatorAdapter($query);

Setting the default value of a Symfony FormType nested in CollectionType

There are a few proposed ways to hack a default value to form fields. The problen gets bigger when handling CollectionTypes, as the underlying objects don’t get constructed automatically. Workarounds are numerous, e.g. simply setting prototype_data on the CollectionType to an instantiated object. Unfortunately, for me, not one of these worked out when working with nested CollectionTypes.

The only way that worked out for me was adding a DataTransformer which checks in the reverseTransform function whether the object to transform is null, and if, set it to a new instance instead. The default values are than set in the constructor of the underlying object or in the reverseTransform function too, depending on your (performance) needs.

I sure hope this gets improved one day, but for now, this workaround is very comprehensible so I would not think about submitting an issue or pull request or even ask why this is necessary. This way, I even have more control over the new objects.

Vaccination controversy introduced by pharma industry because they don't earn enough by vaccination

Well, at least I would like this kind of controversy/conspiracy as it would lead to the opposite effect of what the vaccination-conspiracy is leading to today. Also, this theory would be a lot more supportable by evidence, numbers and logic than the dangerous conspiracy which is spread today.

I sincerly hope that one day, people can relax a bit more over their opinions, find a common midway, depending on the issue, and stop braging with unconventional, illogical and inconsequent ideas.

Cortana vs. Siri #4: Verfügbarkeit

Lange hat es gedauert, doch nun scheint dieser Punkt auch an Cortana zu gehen: Seit nicht allzu langer Zeit ist einerseits Cortana auf Windows 10 Geräten auch in der Schweiz standardmässig verfügbar, ohne dass man gross tricksen muss, und andererseits Siri verfügbar auf Desktop-Geräten und Laptops, die mit dem neusten MacOS ausgerüstet sind. Aber den wharen Punkt gibt es, da insbesondere Cortana bald auch auf iOs- und Adroid-Geräten verfügbar, was von Siri umgekehrt wohl nie behauptet werden kann.

Use Apple Superdrive with Windows

The Apple Superdrive drive is easy to use on Windows. However, the appropriate driver must be installed for this.

Here’s how to do it: Download the Apple Boot Camp Support Software . The file is a zip file, a “zip-compressed folder”, as Windows calls it. Unpack the file and then open the unzipped folder. Go to subfolder / BootCamp / Drivers / Apple. There you will find a file called “AppleODDInstaller64.exe” (you may not see the extension “.exe”). Use this file to install the driver by double-clicking it and following the installation wizard. That’s it! The next time you attach the Apple SuperDrive drive, your Windows should be able to recognize and work with it.

Cortana in der Schweiz!

Mit dem Anniversary Update von Windows 10 ist es endlich soweit – der Sprachassistent von Microsoft ist endlich auch in der Schweiz verfügbar. Zwar versteht Cortana nur Hochdeutsch, doch das ist verständlich. Um Cortana zu aktivieren, benötigt man als erstes das neuste Update von Windows. Dies ist unterdessen auch für Mobilgeräte verfügbar, und kann in den Einstellungen unter Update und Sicherheit und Windows Update installiert werden.

Anschliessend ist für die Aktivierung noch eine kleine Einstellung notwendig. Durch klicken auf das Lupensymbol öffnet sich ein Fenster, in dem man unten links über dem Feedback-Symbol auf das Zahnrad klicken muss, um die Einstellungen für diese Suche zu öffnen. Dort findet man die Einstellung für die Sprache von Cortana. Man wird darauf hingewiesen, dass Region und Sprache nicht mit einer verfügbaren Cortana Sprache übereinstimmen. Dennoch kann man aus einer Liste die Sprache Deutsch (Deutschland) auswählen. Eine erneute Warnung, dass Region und Sprache nicht mit Cortanas Sprache übereinstimmen, und dass einige Features möglicherweise nicht verfügbar sind, kann man getrost wegklicken. Und yay – das wars! Cortana ist ab sofort auf deinem Gerät aktiviert.

Mich hat es vor allem gefreut, dass nun endlich auch der nervtötende {searchTerms} Bug auf meinem Lumia 930 gelöst und verschwunden ist. Bei diesem Fehler öffnete sich mir immer ein Edge-Tab mit einer Google-Suche nach {searchTerms} wenn ich das Lupensymbol berührte.

James Bond’s Salad Dressing

Mix five parts of red-wine vinegar with one part extra-virgin olive oil. The vinegar overload is essential. Add a half clove of garlic, half a teaspoon of Dijon mustard, a good grind of black pepper and a teaspoon of white granulated sugar. Mix well, remove the garlic and dress the salad.

Source: William Boyd, Solo, Jonathan Cape, London 2013, p. 269

Google und Neujahrsvorsätze

Wer im Web sucht, verrät etwas über sich – zumindest wenn er sich nicht dagegen schützt. So zeichnen Google, Bing und Co. jede Suchanfrage auf, zusammen mit Datum, Ort und welche Daten auch immer sie noch kriegen können. Zu unserem Glück bieten sie immer wieder einen Einblick in ihre Daten und zeigen Trends und Highlights, so zum Beispiel auf google.com/trends.

Diese Daten können wichtige Erkenntnisse liefern oder einfach faszinieren. Und sie repräsentieren die Gedanken und Sorgen unserer Gesellschaft. So lässt sich zum Beispiel feststellen, dass kurz vor dem Verkaufsstart von neuen iPhones die Suchanfragen nach “iPhone langsam” exponentiell in die Höhe schnellen.

Jetzt, kurz nach Silvester, jetzt, am Anfang des neuen Jahrs, lässt sich eine ebenso rasch ansteigende Nachfrage nach “Fitness”, “abnehmen” oder “Diät” feststellen. Diese wird auch dieses Jahr – wie alle Jahre zuvor, achten Sie mal auf die Kurve – schnell wieder zurückgehen. Im Frühling wenn das Volk wieder von einer Bikinifigur träumt gehen die Suchanfragen wieder ein wenig rauf, nehmen aber auch diesmal wieder ab – bis zu den Neujahrsvorsätzen!

Welche regelmässigen Kurven finden Sie? Schreiben Sie Ihre Beobachtungen in die Kommentare!

plymouthd: ply-terminal.c:611: ply_terminal_open: Assertion ‘terminal != ((void *)0)’ failed

plymouthd: ply-terminal.c:611: ply_terminal_open: Assertion 'terminal != ((void *)0)' failed

An error message that practically stops the Cubietruck. Fooling around on the keyboard does not help anymore. But there is another solution: Ctrl + Alt + F1

The only problem is that the Lubuntu user interface could not be started. With the magic keyboard command you get to the original Ubuntu command line. From here you can now search for possible causes and fix them.

In my case, an incomplete installation of Java prevented starting the UI. I was able to complete the installation with sudo apt-get -f install after I created a little more space on the hard disk. Then you can either start the user interface by command, or restart the computer with sudo reboot , so that the user interface is activated as usual at startup.