<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
	<channel>
		<title>Lukáš Lalinský</title>
		<description>Random notes and stuff</description>
		<link>http://oxygene.sk</link>
		<language>en</language>
		
		<item>
			<title>AcoustID: Invalid API key?</title>
			<link>http://oxygene.sk/2013/02/acoustid-invalid-api-key/</link>
			<comments>http://oxygene.sk/2013/02/acoustid-invalid-api-key/#disqus_thread</comments>
			
			<category>acoustid</category>
			
			<description>&lt;p&gt;Short version: I'm sorry, but today I had to block some applications from the AcoustID web service. If you were using AcoustID and now get an
&quot;invalid API key&quot; error, please &lt;a href=&quot;mailto:info@acoustid.org&quot;&gt;contact me&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The long version is that when doing some maintenance today, I've found a few applications that are using the service against the usage guidelines.
I knew this would come and I would have to deal with it, I just didn't know when. When starting AcoustID, I have made it really easy to get new
API keys, in hope to avoid copying them
from other open source applications. I've also made it clear on the website, that the web service is intended for non-commercial use. If you
want to use it for commercial purposes, you can contact me and I'm sure we will find a way to make it work, but the web service is by default
intended for non-commercial users.&lt;/p&gt;

&lt;p&gt;So I had to block a few applications and they should start receiving a HTTP 400 error, with the &quot;invalid API key&quot; error message. In order to
avoid this in the future, please register your application on the website and make sure it has a valid e-mail address entered. That way I can
contact you in case of a problem, rather than block the application.&lt;/p&gt;
</description>
			
			<guid isPermaLink="true">http://oxygene.sk/2013/02/acoustid-invalid-api-key/</guid>
			
			<pubDate>Sun, 10 Feb 2013 00:00:00 -0000</pubDate>
		</item>
		
		<item>
			<title>AcoustID code moved to Bitbucket</title>
			<link>http://oxygene.sk/2012/12/acoustid-code-moved-to-bitbucket/</link>
			<comments>http://oxygene.sk/2012/12/acoustid-code-moved-to-bitbucket/#disqus_thread</comments>
			
			<category>acoustid</category>
			
			<description>&lt;p&gt;I was not very happy when GitHub announced that it &lt;a href=&quot;https://github.com/blog/1302-goodbye-uploads&quot;&gt;discontinues project downloads&lt;/a&gt;.
I was using GitHub to host compiled packages for Chromaprint and the AcoustID fingerprinter, as well as release tarballs for all
AcoustID projects, so I had to start looking for alternatives.&lt;/p&gt;

&lt;p&gt;I could continue to use GitHub and host downloads elsewhere, but I like to have all project related files in a central location,
so I've decided to move everything from GitHub to Bitbucket. You can now find all AcoustID source code and packages under
the &lt;a href=&quot;https://bitbucket.org/acoustid&quot;&gt;AcoustID account&lt;/a&gt; on Bitbucket.&lt;/p&gt;

&lt;p&gt;I've not yet decided what to do with the GitHub repositories. They are still there for now,
but should be considered out of date and not used.&lt;/p&gt;
</description>
			
			<guid isPermaLink="true">http://oxygene.sk/2012/12/acoustid-code-moved-to-bitbucket/</guid>
			
			<pubDate>Sat, 29 Dec 2012 00:00:00 -0000</pubDate>
		</item>
		
		<item>
			<title>Alternative MusicBrainz search server</title>
			<link>http://oxygene.sk/2012/11/alternative-musicbrainz-search-server/</link>
			<comments>http://oxygene.sk/2012/11/alternative-musicbrainz-search-server/#disqus_thread</comments>
			
			<category>musicbrainz</category>
			
			<description>&lt;p&gt;If you are working with a local MusicBrainz database and want to search in it,
there aren't that many choices. You can use the internal PostgreSQL full-text
search or you can use the official MusicBrainz search server.&lt;/p&gt;

&lt;p&gt;I've been playing with the idea of a customizable Solr-based solution for a
long time. Creating a simple Solr index with the MusicBrainz data is not
hard, but keeping it up to date is more complicated.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://github.com/lalinsky/mbslave&quot;&gt;mbslave&lt;/a&gt; package now includes a few scripts for creating and
updating a Solr search index. See the &lt;code&gt;README&lt;/code&gt; file for more information on
how to set it up.&lt;/p&gt;

&lt;p&gt;There are a few differences compared to the official MusicBrainz search server:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Everything is in a single index, so there is no need to tell it which entity you are interested in.
If you want to restrict the search to a particular entity, use filter query (e.g. &lt;code&gt;fq=kind:artist&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;It's easy to extend the index to include more fields. There is no configuration file for this yet, but you can edit the &lt;a href=&quot;https://github.com/lalinsky/mbslave/blob/master/mbslave/search.py#L61&quot;&gt;field definition&lt;/a&gt; directly in the source code.&lt;/li&gt;
&lt;li&gt;It doesn't store as much data as the MusicBrainz search server. The intended workflow is to use the database for displaying results.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;I wrote it primarily for my own needs, but if it ends up being useful to people, I'll probably make it more configurable and move to a separate package as it does not necessarily depend on mbslave.&lt;/p&gt;
</description>
			
			<guid isPermaLink="true">http://oxygene.sk/2012/11/alternative-musicbrainz-search-server/</guid>
			
			<pubDate>Fri, 23 Nov 2012 00:00:00 -0000</pubDate>
		</item>
		
		<item>
			<title>AcoustID: Faster fingerprint importing</title>
			<link>http://oxygene.sk/2012/10/acoustid-faster-fingerprint-importing/</link>
			<comments>http://oxygene.sk/2012/10/acoustid-faster-fingerprint-importing/#disqus_thread</comments>
			
			<category>acoustid</category>
			
			<description>&lt;p&gt;Asynchronous importing of user submissions was always a big part of the AcoustID architecture.
It makes things much easier to handle on the server side, allows database maintenance without
turning the service to read-only mode (just delays the imports) and has many other benefits.&lt;/p&gt;

&lt;p&gt;However, people often wanted to get back AcoustIDs for fingerprints they just submitted. It took
about a minute to import the fingerprints, so the only solution was to wait a few minutes
and then look up the submitted fingerprint to see if it's already imported.&lt;/p&gt;

&lt;p&gt;This weekend I've done some changes in how the importing process works and one of
the results is that fingerprints are imported within seconds, not minutes, after they
are submitted. During normal operation, this means that submitted fingerprints will
get imported practically immediately.&lt;/p&gt;

&lt;p&gt;This change made it practical for the submission API call to wait a few seconds and
collect the results of the import process. There is a new parameter &lt;code&gt;wait&lt;/code&gt; which, which
allows the client to set a timeout on how long is it willing to wait for the newly
imported AcoustIDs. If the fingerprints are imported within the timeout, it will
return the AcoustIDs and set the submission status to &quot;imported&quot;. Otherwise, it will
just return the submission ID and the status as &quot;pending&quot;. These IDs can be used to
look up the status later.&lt;/p&gt;

&lt;p&gt;See the documentation on the &lt;a href=&quot;http://acoustid.org/webservice#submit&quot;&gt;&lt;code&gt;submit&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;http://acoustid.org/webservice#submission_status&quot;&gt;&lt;code&gt;submission_status&lt;/code&gt;&lt;/a&gt; API calls for details.&lt;/p&gt;
</description>
			
			<guid isPermaLink="true">http://oxygene.sk/2012/10/acoustid-faster-fingerprint-importing/</guid>
			
			<pubDate>Sun, 21 Oct 2012 00:00:00 -0000</pubDate>
		</item>
		
		<item>
			<title>Dropbox folder icon in GNOME 3</title>
			<link>http://oxygene.sk/2012/10/dropbox-folder-icon-in-gnome-3/</link>
			<comments>http://oxygene.sk/2012/10/dropbox-folder-icon-in-gnome-3/#disqus_thread</comments>
			
			<category>tools</category>
			
			<description>&lt;p&gt;I upgraded to GNOME 3 just over a week ago and when installing the
&lt;a href=&quot;http://tiheum.deviantart.com/art/Faenza-Icons-173323228&quot;&gt;Feanza icon theme&lt;/a&gt;, I noticed that there is a nice Dropbox folder
icon included. Nautilus allows you to set icon for any folder,
but only lets you select a specific image file, which doesn't look
particularly good when scaled.&lt;/p&gt;

&lt;p&gt;GNOME icon themes have icons in multiple sizes for each icon, so
rather then specific image files, it's better to use generic icon
names. I didn't find any GUI to assign an icon name to a folder,
but fortunately there is a way to do it using the
&lt;code&gt;gvfs-set-attribute&lt;/code&gt; tool:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;gvfs-set-attribute ~/Dropbox metadata::custom-icon-name folder-dropbox
&lt;/code&gt;&lt;/pre&gt;
</description>
			
			<guid isPermaLink="true">http://oxygene.sk/2012/10/dropbox-folder-icon-in-gnome-3/</guid>
			
			<pubDate>Sat, 20 Oct 2012 00:00:00 -0000</pubDate>
		</item>
		
		<item>
			<title>Twisted Trial and Jenkins</title>
			<link>http://oxygene.sk/2012/10/twisted-trial-and-jenkins/</link>
			<comments>http://oxygene.sk/2012/10/twisted-trial-and-jenkins/#disqus_thread</comments>
			
			<category>tools</category>
			
			<description>&lt;p&gt;It's not completely obvious how to configure a Twisted-based job that uses &lt;a href=&quot;http://twistedmatrix.com/documents/current/core/howto/testing.html&quot;&gt;Trial&lt;/a&gt; for running tests in Jenkins, so hopefully this post will save somebody a little time in the future.&lt;/p&gt;

&lt;p&gt;Jenkins needs JUnit-style XML file to parse test results. You can get that output from Trial, if you pass the results thought &lt;a href=&quot;http://pypi.python.org/pypi/python-subunit&quot;&gt;subunit&lt;/a&gt; with &lt;a href=&quot;http://pypi.python.org/pypi/junitxml&quot;&gt;junitxml&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Debian-based distributions have those two modules packaged, so you can install them with &lt;code&gt;apt-get&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;apt-get install python-subunit python-junitxml
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Elsewhere you can use &lt;code&gt;pip&lt;/code&gt; or &lt;code&gt;easy_install&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;pip install python-subunit junitxml
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then in your Jenkins configuration, you can use the following command and let Jenkins know to collect the test results from &lt;code&gt;results.xml&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;trial --reporter=subunit MYPACKAGE | subunit2junitxml &amp;gt;results.xml
&lt;/code&gt;&lt;/pre&gt;
</description>
			
			<guid isPermaLink="true">http://oxygene.sk/2012/10/twisted-trial-and-jenkins/</guid>
			
			<pubDate>Wed, 17 Oct 2012 00:00:00 -0000</pubDate>
		</item>
		
		<item>
			<title>Extending the SQLAlchemy SQL expression language</title>
			<link>http://oxygene.sk/2012/09/extending-the-sqlalchemy-sql-expression-language/</link>
			<comments>http://oxygene.sk/2012/09/extending-the-sqlalchemy-sql-expression-language/#disqus_thread</comments>
			
			<category>programming</category>
			
			<description>&lt;p&gt;The SQL expression language from SQLAlchemy is already very flexible and
allows you to build almost any standard SQL query, but sometimes you just
need to use a SQL extension that isn't supported by SQLAlchemy.&lt;/p&gt;

&lt;p&gt;Suppose I have a very simple music datababse and I want a list of all artists
with their latest album name. Oracle has special aggregate functions
&lt;a href=&quot;http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions056.htm&quot;&gt;&lt;code&gt;FIRST&lt;/code&gt;/&lt;code&gt;LAST&lt;/code&gt;&lt;/a&gt;, which together with the &lt;code&gt;KEEP&lt;/code&gt; clause can help with queries like
this, but unfortunately it isn't supported by the Oracle dialect in SQLAlchemy.
The SQL query would look like this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sql&quot;&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;artist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;MIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;KEEP&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DENSE_RANK&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;LAST&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BY&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;release_date&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;album&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;GROUP&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BY&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;artist&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Recently, I've learned that it's possible to extend the &lt;a href=&quot;http://docs.sqlalchemy.org/en/rel_0_7/core/compiler.html&quot;&gt;SQL compiler&lt;/a&gt; and
add support for custom clauses that SQLAlchemy doesn't understand natively.
In my specific case of the &lt;code&gt;KEEP&lt;/code&gt; clause, I need this code to make it work:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;itertools&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sqlalchemy.util&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to_list&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sqlalchemy.sql.expression&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ColumnElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ClauseList&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sqlalchemy.ext.compiler&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compiles&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Keep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ColumnElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;order_by&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;func&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;order_by&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ClauseList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;order_by&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@property&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@property&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;_from_objects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;itertools&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_from_objects&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;order_by&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;keep_first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;order_by&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Keep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;order_by&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;keep_last&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;order_by&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Keep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;order_by&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;


&lt;span class=&quot;nd&quot;&gt;@compiles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Keep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_keep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;keep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kwargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; KEEP (DENSE_RANK &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; ORDER BY &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;)&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;keep&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&amp;quot;FIRST&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keep&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;LAST&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;keep&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;order_by&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;With this, I could simply use &lt;code&gt;keep_first()&lt;/code&gt; and &lt;code&gt;keep_last()&lt;/code&gt; as any
other SQL expression functions. For example, the above SQL query would
have been written like this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;&lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Album&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;artist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;keep_last&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Album&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Album&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;release_date&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;\
    &lt;span class=&quot;n&quot;&gt;group_by&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Album&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;artist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;The main advantage of having it all written as a SQL expression is that
I don't need to know the actual column names, which get more and more
complicated once you have some joins and subqueries in the SQL expression.&lt;/p&gt;
</description>
			
			<guid isPermaLink="true">http://oxygene.sk/2012/09/extending-the-sqlalchemy-sql-expression-language/</guid>
			
			<pubDate>Tue, 25 Sep 2012 00:00:00 -0000</pubDate>
		</item>
		
		<item>
			<title>Offline for the next four weeks</title>
			<link>http://oxygene.sk/2012/09/offline-for-the-next-four-weeks/</link>
			<comments>http://oxygene.sk/2012/09/offline-for-the-next-four-weeks/#disqus_thread</comments>
			
			<description>&lt;p&gt;I'm starting my hiking trip though Spain tomorrow, so I'll be online very sporadically during the next four weeks and I'll probably not answer emails.&lt;/p&gt;
</description>
			
			<guid isPermaLink="true">http://oxygene.sk/2012/09/offline-for-the-next-four-weeks/</guid>
			
			<pubDate>Fri, 07 Sep 2012 00:00:00 -0000</pubDate>
		</item>
		
		<item>
			<title>TagLib 1.8 released</title>
			<link>http://oxygene.sk/2012/09/taglib-1-8-released/</link>
			<comments>http://oxygene.sk/2012/09/taglib-1-8-released/#disqus_thread</comments>
			
			<category>taglib</category>
			
			<description>&lt;p&gt;I'm sorry this took longer than expected, but I've just released the
final version of TagLib 1.8. There are a few changes compared to the
beta version, see the change log below.&lt;/p&gt;

&lt;p&gt;Download:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/downloads/taglib/taglib/taglib-1.8.tar.gz&quot;&gt;Source Code Tarball&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;If you find any problems, please report them at the &lt;a href=&quot;https://github.com/taglib/taglib/issues&quot;&gt;GitHub bug tracker&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Changes in 1.8 final:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Added support for OWNE ID3 frames.&lt;/li&gt;
&lt;li&gt;Changed key validation in the new PropertyMap API.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ID3v1::Tag::setStringHandler&lt;/code&gt; will no londer delete the previous handler, the caller is responsible for this.&lt;/li&gt;
&lt;li&gt;File objects will also no longer delete the passed IOStream objects. It should be done in the caller code after the File object is no longer used.&lt;/li&gt;
&lt;li&gt;Added &lt;code&gt;ID3v2::Tag::setLatin1StringHandler&lt;/code&gt; for custom handling of latin1-encoded text in ID3v2 frames.&lt;/li&gt;
&lt;li&gt;Fixed validation of ID3v2 frame IDs (IDs with '0' were ignored).&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Changes in 1.8 beta:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;New API for accessing tags by name.&lt;/li&gt;
&lt;li&gt;New abstract I/O stream layer to allow custom I/O handlers.&lt;/li&gt;
&lt;li&gt;Support for writing ID3v2.3 tags.&lt;/li&gt;
&lt;li&gt;Support for various module file formats (MOD, S3M, IT, XM).&lt;/li&gt;
&lt;li&gt;Support for MP4 and ASF is now enabled by default.&lt;/li&gt;
&lt;li&gt;Started using atomic int operations for reference counting.&lt;/li&gt;
&lt;li&gt;Added methods for checking if WMA and MP4 files are DRM-protected.&lt;/li&gt;
&lt;li&gt;Added &lt;code&gt;taglib\_free&lt;/code&gt; to the C bindings.&lt;/li&gt;
&lt;li&gt;New method to allow removing pictures from FLAC files.&lt;/li&gt;
&lt;li&gt;Support for reading audio properties from ALAC and Musepack SV8 files.&lt;/li&gt;
&lt;li&gt;Added replay-gain information to Musepack audio properties.&lt;/li&gt;
&lt;li&gt;Support for APEv2 binary tags.&lt;/li&gt;
&lt;li&gt;Many AudioProperties subclasses now provide information about the total number of samples.&lt;/li&gt;
&lt;li&gt;Various small bug fixes.&lt;/li&gt;
&lt;/ul&gt;

</description>
			
			<guid isPermaLink="true">http://oxygene.sk/2012/09/taglib-1-8-released/</guid>
			
			<pubDate>Thu, 06 Sep 2012 00:00:00 -0000</pubDate>
		</item>
		
		<item>
			<title>Blog moved to Jekyll</title>
			<link>http://oxygene.sk/2012/09/blog-moved-to-jekyll/</link>
			<comments>http://oxygene.sk/2012/09/blog-moved-to-jekyll/#disqus_thread</comments>
			
			<description>&lt;p&gt;Just finished moving this blog from WordPress to static files generated using Jekyll, with Disqus for comments. Please let me know if you spot a broken link or some other problem.&lt;/p&gt;
</description>
			
			<guid isPermaLink="true">http://oxygene.sk/2012/09/blog-moved-to-jekyll/</guid>
			
			<pubDate>Wed, 05 Sep 2012 23:33:00 -0000</pubDate>
		</item>
		
	</channel>
</rss>

