In anticipation of two busy conferences in the San Francisco Bay Area, the TiZen Developer Conference 2012 and the Ubuntu Developer Summit for the Quetzal release, I prepared myself by arriving one week earlier. This avoids the stress of a long distance flight immediately before conferences start, but also helps to adjust yourself to the environment (e.g., get used to public transport, find your ways around the area, get used to the food, etc.).
My flight to California was somewhat jinxed. Instead of getting a direct flight to SFO from an European airport, I had to change over in Miami. So instead of 12 flight hours, I was already up to 17 hours. Then the flight got delayed, and I of course missed the connection flight. Being rescheduled to the next flight meant another 5 hours of extra waiting time and arriving at SFO briefly before midnight. Which means no public transport for you. Luckily, I had informed Quim Gil about my additional delays (thanks to free WiFi at Miami airport), and being the good friend that he is, he decided to pick me up from SFO.
On the next day (a warm Sunday), I had time to visit the Computer History Museam in Mountain View. Later that evening, Quim, Henri and I met for a few drinks, the outcome being this Maemo thread. Sadly, the thread itself has seemingly no positive outcome yet.
On Monday, it was time to go to San Francisco, where I spent the next days (mostly) working and preparing my TiZen session for next week. It was great to experience San Francisco from a non-tourist point of view (though I still had to visit Johnny Rockets together with Alberto, Łukasz, Kat and Dave, the milkshakes really are that good). My highlight of the week was perhaps the lunch with the ever friendly Yorba guys on Friday. I saw their awesome new T-shirts, but sadly they’re for employees-only.
On the weekend, I met with Lokesh and we drove down to Santa Cruz (great beach, lots of surfers, too) and from there to Monterey, on the famous 17-Mile Drive. I even dared to (very briefly!) swim in the Pacific Ocean, another first for me. The Pacific made me pay my courage in blood though (nothing too bad, just an annoying cut at my heel).
Then, well rested and all that, it was time for the conferences. Since there was only one keynote for Monday evening at the TiZen Developer Conference, I spent most of the day at UDS. The one thing to notice was probably that UDS had way more developers than TiZen, and to my surprise, even some high profile GNOME developers attended UDS. So much for all the silly fights about Ubuntu not being GNOME etc. I also met Daniel d'Andrader again, which was nice.
For the other two days, it was always a bit of back-and-forth between UDS and TiZen. UDS had the better food (breakfast, hm!), but TiZen probably had the better parties (California Academy of Science comes to mind). On Thursday I started to feel exhausted and on Friday, I was glad UDS was to be over soon. The beach party (without a beach) totally killed it.
The flight back was uneventful. After two weeks in California, with the second one being extremely stressful, I was glad to finally land in Berlin again.
Over the last couple of weeks I have reimplemented just enough of the C++ libglom code as Java in Online Glom‘s gwt-glom, removing the need for java-libglom (which wrapped libglom for Java via SWIG). It’s now working and deployed on the Online Glom test server.
This makes both development and deployment much easier. It also made the source code all camelCase so it’s not offensive to the eyes of Java coders.
To replace libglom’s use of GdaSqlBuilder, I used jOOQ. That worked well, thanks to its maintainer, Lukas Eder, who was very helpful and who quickly added some API that I needed.
Now that the code is all Java I really hope that more people will look over the code and point out anything that can be improved. I still don’t know Java like I know C++ so please don’t be shy about telling me that I have made mistakes.
GWT, Javascript, and serialization
Removing the use of java-libglom let me simplify the code, because I can now send object, such as LayoutItem, to the client without needing to copy it into a separate LayoutItemDTO object that existed just because the original wasn’t serializable, so it could be sent from the server (Java) to the client (JavaScript, compiled from Java).
However, this raised some new issues. I wanted some of the objects to contain some extra cached data, so that the client code did not have to calculate it itself, often by retrieving some other related object. Right now these are extra member variables in the classes, but that prevents me from splitting the code off into a new java-glom library.
Furthermore, any class that is sent between the client and server must fully conform to the requirements of the GWT Java-to-JavaScript compiler, even if that method will not actually be run on the server. For instance, I tried to add clone() methods, for use on the server, but that broke the JavaScript compilation because it doesn’t have an equivalent for Object.clone().
Those restrictions on the Java code that is allowable on the client side (because it will be compiled to JavaScript) were particularly awkward when the compiler (or Maven, or something) refused to give me clues about what was wrong. For instance, it took me 2 frustrating days to fix this small error by breaking the code apart until only the problem code remained. At other times, there was no real error on stdout, but there were clues (in a variety of hard-to-read formats) in the HTML generated by mvn site. Or sometimes, I could see errors when building inside Eclipse, but not outside.
The GWT system works great, but something is inconsistent about how it shows errors, and it can’t be right that some compilation errors only show up when running, rather than when building.
Next steps
As much as I would like to move on to implementing editing, I need to spend some time now on getting some regression tests set up in the maven build. These must create and run temporary PostgreSQL database instances like I do in the Glom autotools build. For instance, I need to check that the new SQL-building code, using jOOQ, is really safe from SQL injection like the libglom code seems to be.
My recent changes also caused the OnlineGlomService async API to be particularly inefficient, sometimes sending far more data back to the server than should be necessary. I will try to avoid that and try to make this API smaller, to avoid so many round trips.
The first day started slowly, with only one keynote in the evening. I wasn’t very happy with it, a proper keynote would have focused more on the visions and goals of TiZen, not so much on Linux or Android, or Microsoft.
On the second day, my mind was mostly occupied with my own session, “Challenges of mobile text input”, in the afternoon. It was good that speakers were informed early enough about the whole process, and the presentation templates were available long enough before the event. Even with the cold color scheme, I kind of like the clean TiZen design in the templates (though I still can’t get used to the name “Ti-Zen”).
Two hours or so before my session, I had one technician help me upload my slides to the room’s PC. It’s great to not have to use your own laptop. Instead of worrying until the last minute whether everything will work, you know it just will, and if it doesn’t, it is not your task to fix it. Not having this typical presenter’s crisis helps to focus on the content of your session and also helps to stay calm.
I was quite happy with my presentation, even though I was hoping for more input method developers in the audience. You can find the slides on the Maliit wiki, video (or at least audio) should be available at some later point, too.
On the last day, every attendee could get a TiZen developer device. I was surprised it didn’t have “Intel Inside”, but the ARM Cortex9 with the Mali GPU is interesting hardware nevertheless. Perhaps not too surprising for a HTML5 platform, it also comes with a speedy and actually useful mobile browser from the start. Even if it is uncertain at this point whether TiZen will end being a success, I am looking forward to see actual TiZen consumer devices.
Thanks to the Linux Foundation for sponsoring me, and thanks to Brian Warner again for helping with the organising bits.
Already covered in the news from LGM was the release of GIMP 2.8, and that GIMP 2.10 will be fully GEGLified. The goat-invasion branch which has most of that work, the result of 3 weeks of pippin and mitch on a couch hacking together, has already landed in master. This means that GIMP now has support for high bit-depth workflows for most operations. Finally.
Putting the goat in MyPaint
During LGM I started working on using GEGL in MyPaint. I have already mentioned this idea several times, so it was time to stop talking and get hacking.
As a first step in making use of GEGL I wanted to replace the current surface implementation with one based on GeglBuffer. Since GeglBuffer already provides tiling, and can store any buffer data supported by Babl this turned out to be easy. Øyvind (pippin) added the semi-quirky pixel format we currently use* in MyPaint to Babl, and I was able to get a rough working GEGL based Surface implementation the first evening.
* RGBA premultiplied alpha, in 16 bit unsigned integers with 2^15 being the maximum value.
The next couple of days went to moving to the GeglBufferIterator API instead of gegl_buffer_{get,set} to have zero-copy access to improve performance, and improving GEGL and GEGL-GTK so that some of the hacks in the initial implementation could be removed.
Most of the work is in the gegl branch of MyPaint. A simple test application, mypaint-gegl.py, is included, and you can read README.gegl for how to try it out. Warning: only intended for curious developers at this stage.
A lots of work remains to be done for MyPaint to be able to fully use GEGL. The progress is tracked in two bugs, one for MyPaint work and one for GEGL issues. Because one cannot combine PyGObject with PyGTK, it will likely not be possible to fully integrate GEGL in MyPaint before porting to PyGI and GTK+ 3.
Oh, in case the goat references are lost on you – check the GEGL page on wikipedia.
Motivated by the new Blackberry 10 virtual keyboard, I decided to spent a couple of hours on a proof of concept, this video being the result.
I had to hack the Presage engine a bit to provide word prediction in a similar fashion to what you see in the 2-3 seconds of the Blackberry video. Then I added some space between the rows of the keyboard, so that I could place additional word ribbons there. The word candidates appear next to their starting letters, though it’s only one candidate per letter. I need to find a better solution here, but then again Blackberry guys also haven’t solved it either ;–) Tapping on the word candidates inserts then into the text editor (no gestures, for now).
The code is very hackish, certainly nothing I would publish. I am going to put it onto a tablet so that I can show it around to you guys at the TiZen Developer Conference or the Ubuntu Developer Summit.
Jon is going to bring a camcorder on Sunday, so perhaps we can actually record a real, youtube-worthy video then.
I am going to speak about mobile text input at the TiZen Developer Conference (7-9 May, San Francisco, CA). My session is scheduled for Tuesday afternoon (PDF).
I had planned to only focus on the technical aspects, but I am also going to talk about other aspects, such as the media coverage a cleverly designed text input method can achieve, and which features are apparently important to consumers.
The most important feature is, unsurprisingly perhaps, the overall performance: How fast can consumers insert or manipulate text on their mobile devices — while still being accurate? I will explain techniques that can help to improve responsiveness, accuracy and speed of a virtual keyboard.
I’ll be in the bay area until end of next week and I am generally interested to discuss the finer details of (text) input methods, accessibility or display servers and how one could improve the situation for accessibility on Linux. Contact me on Twitter in case you want to meet up and go somewhere for dinner (or drinks) in the beautiful city of San Francisco!
If you just upgraded to Ubuntu 12.04 and your PS3 or Sony TV stopped showing videos, the work-around is to uninstall gstreamer0.10-plugins-bad-multiverse. See bug 672439 for the details.
The bright side is that for the first time ever, we have a recent Ubuntu shipping the latest version of Rygel.
It's a common design to use full text search engines only for free text searches, but to store the actual structured data in a separate database. Such designs come at a cost. Therefore Openismus asked me to build upon my previous post, where I analyzed several FTS engines. This time I'll research if we could use the full text search index itself as our primary data store.
Relations
A first obvious limitation is the lack of joins. So to use the FTS index as
data store, you must denormalize your data. That is, instead
of storing your movie database in distinct entity tables like Movie and
Artist, linked by relationship tables like isLeadActor or isDirector,
you must find a way to put everything into one single flat table. This isn't
entirely nice in terms of redundancy and consistency. On the other hand joining
tables is what makes relational databases slow and hinders distributing them
across servers. Is there someone whispering "NoSQL"? Well. Yes, while I
absolutely dislike their striking marketing: They are on to something, and
with our journey today we enter their land.
Seems I've lost myself in chatting, so back on topic. So to store data in a FTS index we must denormalize our data. Luckily they make it easier than it sounds. In opposition to the relational model, there is no need to create complex relationships, just to assign more than only one actor or director to a movie: When adding artists to your movie you just tag each name with the proper field prefix before adding it to the index, and you are done. FTS engines natively support multi-value fields!
With some additional effort it also should be possible to store more structured
data in those multi-value fields, things like (release-date, country), or
(actor, role): You'd add more prefixes and use the positional information
stored for phrase searches to reliably identify those fields. Sadly my time is
too limited to research this more in detail, but the Internet surely has
documents about this. Well, or for additional fun you can try to figure it out
yourself.
Exact Matches
You can just add unanalyzed fields and use term queries on them like kamstrup pointed out.
Data Types
So we've learned that lack of relations isn't much of a problem for many useful datasets, but structured data is not only about relationships, it also is about data types. Full Text Search engines only support lexicographical order, so they surely fail for dates and numbers. You surely cannot use them to find documents within a given range!
I am sorry to disappoint you. The people researching FTS are smarter than that.
Actually properly sorting and ranging dates, while only using lexicographic
order is trivial. Most probably you have done it yourself already. Simply store
your dates in ISO format, that is YYYY-MM-DDThh:mm:ss.SSSNNN or any prefix of
this, and you are done. Omit the separators if you prefer. ISO-8601 explicitly
is designed for lexicographic sorting.
So how do you do this with numbers? You could prefix them, for instance with zeros, to get a fixed width. This works reasonably if you know your number ranges, and in most cases you do. Sometimes you know the range from your application's context, e.g. the first known celluloid film was recorded in 1888. More easily you just use your technical limits, like [-263..263-1] for long integers. While first experiments really followed that approach, padding numbers with up to 18 zeros isn't exactly efficient or pretty. Also we didn't talk about floating point numbers yet. Therefore FTS engines like Lucene or Xapian provide more efficient mechanisms for turning numbers into sortable strings. First they write a prefix indicating number precision (64 bit, 32 bit, 10 bit, ...). Then they convert the numbers to some unsigned format, and apply some kind of base-128 encoding to the resulting bytes. The most significant bit gets stored first. For floating point numbers they shuffle some bits of the number's IEEE-754 representation. The resulting, sortable 64 bit integer then is encoded like any other number. You can consult Lucene's documentation, and the source code of Lucene::NumericUtils, or Xapian::sortable_serialise for details.
Benchmarks
Hope I didn't lose you with all this theory, now it is benchmark time!
To test how useful FTS engines are for storing arbitrary data I've extended my previous benchmark to better support range searches, and to support exact matching of fields. I've also added Michal Hruby's patch for supporting prefix searches. Since the prefix search gives countless hits, the query results consistently are limited to 10.000 rows now. I've dropped QtCLucene for now since it doesn't seem to support numeric range searches and such. It was forked from Java Lucene a long time ago. For SQLite I ran two sets of tests: bm_sqlite doesn't create indices for fields like movie title or artist names. Since such setup is unfair when comparing with FTS engines, the second set bm_sqlite_index creates indices for all fields we perform lookups for. For tracker we again test the Nepomok media ontology (bm_tracker) and a optimized ontology (bm_tracker_flat), that attaches all properties to the same RDF class. I had to disable prefix searches for bm_tracker: The query ran for more than 2 hours on the dataset with 17k movies. I seriously wish I'd get sponsored to improve Tracker's data model!
Source code still is in the fts-benchmark repository, tagged as
release/0.3.
Results and Discussion
Each query got run 7 times on 5 different data sets. This time I didn't take
the mean of the query execution times. The individual results of each dataset
are grouped together and labeled with qxx_t1 to qxx_t7. Data and result
sets grow with each group.
Also be careful when reading the charts as time is scaled logarithmically. You might want to consult the raw data tables below for details. Please keep in mind that the basic goal of this benchmarks is to test scalability, not raw performance. Therefore I don't mind much if an engine is 10 times slower than another for small data sets. Constant performance is the ideal result.
You'll also notice that some charts have gaps for bm_tracker. Like explained above I had to skip bm_tracker for few data sets, as tracker took way to long to perform those benchmarks.
![rating:[90 TO 99]](http://taschenorakel.de/files/fts-benchmark/ftsds1.png)
Lucene++ appears significantly slower than its competition for small data sets, but then gives comparable results for data sets with more than 3,000 movies. Still I would not overrate this finding: We are talking about lookup times in the range of 10 ms. That's still pretty fast and close to measurement limits like the spikes in the other engine's results show.
![release:[1999/01/01 TO 1999/09/30]](http://taschenorakel.de/files/fts-benchmark/ftsds2.png)
This results are similar to the rating:[90 TO 99] query.

For this query you see the importance of having an index for your lookup keys: Performance of bm_lucene++ and bm_sqlite_index remains almost constant, while effort of the other engines grows dramatically as the data size grows.
Xapian's bad performance comes as a surprise, but actually I am to blame here:
For stupid reasons I've implemented this very search as range search in
Lucene++ and Xapian (release:[1999/03/31 TO 1999/03/31]). As the results
indicate Lucene++ seems to putting more effort into optimizing range searches,
and compensates my mistake.

Similar results as for release=1999/03/31, only that Xapian behaves as
expected now. When given a proper query it also shows constant lookup time for
exact phrase searches.

With this query you see the advantage you get from using denormalized tables: Lucene++ and Xapian just are as efficient as in the previous tests, but as a not so big surprise Tracker with the flat ontology now beats all remaining engines, including bm_sqlite_index.

Performance of the different engines is similar to each other when performing prefix searches.
Raw Result Data
| rating:[90 TO 99] - 9 movies, 3 matches | |||||||
|---|---|---|---|---|---|---|---|
| t1 | t2 | t3 | t4 | t5 | t6 | t7 | |
| bm_lucene++ | 12.333 ms | 10.409 ms | 9.885 ms | 9.821 ms | 10.221 ms | 9.840 ms | 9.986 ms |
| bm_sqlite | 0.196 ms | 0.169 ms | 0.169 ms | 0.173 ms | 0.166 ms | 0.167 ms | 0.167 ms |
| bm_sqlite_index | 0.207 ms | 0.183 ms | 0.172 ms | 0.192 ms | 0.193 ms | 0.173 ms | 0.172 ms |
| bm_tracker | 0.992 ms | 0.655 ms | 0.582 ms | 0.589 ms | 0.554 ms | 0.549 ms | 0.525 ms |
| bm_tracker_flat | 0.693 ms | 0.463 ms | 0.437 ms | 0.461 ms | 0.450 ms | 0.443 ms | 0.436 ms |
| bm_xapian | 0.242 ms | 0.201 ms | 0.200 ms | 0.198 ms | 0.200 ms | 0.199 ms | 0.197 ms |
| rating:[90 TO 99] - 1,099 movies, 17 matches | |||||||
| t1 | t2 | t3 | t4 | t5 | t6 | t7 | |
| bm_lucene++ | 12.949 ms | 13.057 ms | 12.981 ms | 13.018 ms | 13.150 ms | 12.840 ms | 12.644 ms |
| bm_sqlite | 0.696 ms | 0.546 ms | 0.516 ms | 0.530 ms | 0.515 ms | 0.518 ms | 0.522 ms |
| bm_sqlite_index | 0.448 ms | 0.234 ms | 0.231 ms | 0.237 ms | 0.236 ms | 0.231 ms | 0.231 ms |
| bm_tracker | 5.051 ms | 4.485 ms | 4.441 ms | 4.486 ms | 4.425 ms | 4.831 ms | 4.828 ms |
| bm_tracker_flat | 1.465 ms | 1.133 ms | 1.110 ms | 1.104 ms | 1.108 ms | 1.108 ms | 1.108 ms |
| bm_xapian | 1.445 ms | 1.285 ms | 1.159 ms | 7.824 ms | 1.878 ms | 1.669 ms | 1.393 ms |
| rating:[90 TO 99] - 3,216 movies, 35 matches | |||||||
| t1 | t2 | t3 | t4 | t5 | t6 | t7 | |
| bm_lucene++ | 14.287 ms | 13.596 ms | 13.453 ms | 13.912 ms | 13.875 ms | 14.559 ms | 13.981 ms |
| bm_sqlite | 3.524 ms | 4.110 ms | 4.129 ms | 1.916 ms | 1.732 ms | 2.300 ms | 9.584 ms |
| bm_sqlite_index | 0.423 ms | 2.036 ms | 4.617 ms | 4.577 ms | 0.388 ms | 1.957 ms | 7.981 ms |
| bm_tracker | 12.776 ms | 11.816 ms | 12.449 ms | 11.755 ms | 11.762 ms | 11.983 ms | 11.764 ms |
| bm_tracker_flat | 2.935 ms | 2.517 ms | 2.374 ms | 2.264 ms | 2.250 ms | 2.261 ms | 2.258 ms |
| bm_xapian | 9.292 ms | 2.702 ms | 10.573 ms | 6.773 ms | 3.098 ms | 11.438 ms | 3.035 ms |
| rating:[90 TO 99] - 17,251 movies, 260 matches | |||||||
| t1 | t2 | t3 | t4 | t5 | t6 | t7 | |
| bm_lucene++ | 58.996 ms | 56.894 ms | 62.172 ms | 57.028 ms | 57.255 ms | 57.540 ms | 57.259 ms |
| bm_sqlite | 36.682 ms | 28.260 ms | 34.116 ms | 34.786 ms | 35.195 ms | 35.813 ms | 35.221 ms |
| bm_sqlite_index | 45.802 ms | 62.460 ms | 31.603 ms | 32.982 ms | 33.302 ms | 31.904 ms | 31.656 ms |
| bm_tracker | 67.022 ms | 64.609 ms | 64.649 ms | 65.243 ms | 64.183 ms | 64.887 ms | 64.283 ms |
| bm_tracker_flat | 14.730 ms | 14.179 ms | 14.132 ms | 14.221 ms | 14.248 ms | 20.225 ms | 35.888 ms |
| bm_xapian | 94.872 ms | 47.067 ms | 85.202 ms | 28.575 ms | 142.854 ms | 48.562 ms | 52.567 ms |
| rating:[90 TO 99] - 121,587 movies, 1,510 matches | |||||||
| t1 | t2 | t3 | t4 | t5 | t6 | t7 | |
| bm_lucene++ | 283.122 ms | 392.801 ms | 382.164 ms | 403.929 ms | 384.512 ms | 408.292 ms | 361.548 ms |
| bm_sqlite | 293.488 ms | 236.636 ms | 249.677 ms | 232.674 ms | 270.198 ms | 282.806 ms | 218.726 ms |
| bm_sqlite_index | 231.638 ms | 311.523 ms | 198.781 ms | 279.063 ms | 219.294 ms | 192.589 ms | 276.822 ms |
| bm_tracker | - | - | - | - | - | - | - |
| bm_tracker_flat | 181.478 ms | 272.453 ms | 251.730 ms | 256.744 ms | 293.067 ms | 230.615 ms | 245.113 ms |
| bm_xapian | 376.176 ms | 417.637 ms | 411.263 ms | 366.596 ms | 393.168 ms | 372.888 ms | 412.411 ms |
| release:[1999/01/01 TO 1999/09/30] - 9 movies, 2 matches | |||||||
| t1 | t2 | t3 | t4 | t5 | t6 | t7 | |
| bm_lucene++ | 18.768 ms | 10.167 ms | 10.799 ms | 10.215 ms | 10.443 ms | 10.917 ms | 10.210 ms |
| bm_sqlite | 0.165 ms | 0.166 ms | 0.164 ms | 0.164 ms | 0.168 ms | 0.164 ms | 0.164 ms |
| bm_sqlite_index | 0.175 ms | 0.175 ms | 0.170 ms | 0.169 ms | 0.169 ms | 0.169 ms | 0.170 ms |
| bm_tracker | 1.074 ms | 0.569 ms | 0.546 ms | 0.561 ms | 0.544 ms | 0.549 ms | 0.546 ms |
| bm_tracker_flat | 0.877 ms | 0.480 ms | 0.460 ms | 0.458 ms | 0.461 ms | 0.458 ms | 0.456 ms |
| bm_xapian | 0.183 ms | 0.175 ms | 0.175 ms | 0.178 ms | 0.178 ms | 0.180 ms | 0.175 ms |
| release:[1999/01/01 TO 1999/09/30] - 1,099 movies, 34 matches | |||||||
| t1 | t2 | t3 | t4 | t5 | t6 | t7 | |
| bm_lucene++ | 19.154 ms | 19.449 ms | 18.811 ms | 19.419 ms | 19.692 ms | 19.315 ms | 18.862 ms |
| bm_sqlite | 0.691 ms | 0.686 ms | 0.684 ms | 0.687 ms | 0.690 ms | 0.702 ms | 0.698 ms |
| bm_sqlite_index | 0.365 ms | 0.311 ms | 0.317 ms | 0.312 ms | 0.311 ms | 0.312 ms | 0.313 ms |
| bm_tracker | 6.231 ms | 5.543 ms | 5.734 ms | 5.522 ms | 5.663 ms | 5.538 ms | 5.465 ms |
| bm_tracker_flat | 1.998 ms | 1.494 ms | 1.466 ms | 1.469 ms | 1.470 ms | 1.454 ms | 1.469 ms |
| bm_xapian | 5.336 ms | 1.590 ms | 7.241 ms | 1.977 ms | 2.651 ms | 4.013 ms | 2.544 ms |
| release:[1999/01/01 TO 1999/09/30] - 3,216 movies, 84 matches | |||||||
| t1 | t2 | t3 | t4 | t5 | t6 | t7 | |
| bm_lucene++ | 32.202 ms | 31.513 ms | 31.362 ms | 30.894 ms | 31.345 ms | 31.741 ms | 31.518 ms |
| bm_sqlite | 6.169 ms | 2.645 ms | 7.560 ms | 20.764 ms | 10.385 ms | 13.278 ms | 10.206 ms |
| bm_sqlite_index | 19.176 ms | 4.358 ms | 12.576 ms | 15.448 ms | 15.745 ms | 5.572 ms | 5.770 ms |
| bm_tracker | 15.507 ms | 14.803 ms | 13.629 ms | 15.465 ms | 13.930 ms | 14.515 ms | 13.652 ms |
| bm_tracker_flat | 3.956 ms | 3.488 ms | 3.183 ms | 3.176 ms | 3.213 ms | 3.193 ms | 3.157 ms |
| bm_xapian | 18.414 ms | 5.874 ms | 11.902 ms | 12.932 ms | 19.995 ms | 21.098 ms | 13.009 ms |
| release:[1999/01/01 TO 1999/09/30] - 17,251 movies, 374 matches | |||||||
| t1 | t2 | t3 | t4 | t5 | t6 | t7 | |
| bm_lucene++ | 93.892 ms | 93.900 ms | 93.549 ms | 93.555 ms | 93.924 ms | 94.396 ms | 93.795 ms |
| bm_sqlite | 37.831 ms | 44.905 ms | 47.617 ms | 45.894 ms | 43.796 ms | 45.752 ms | 47.048 ms |
| bm_sqlite_index | 48.475 ms | 47.805 ms | 43.046 ms | 47.393 ms | 44.689 ms | 47.842 ms | 54.208 ms |
| bm_tracker | 72.507 ms | 72.667 ms | 72.233 ms | 73.570 ms | 72.997 ms | 72.991 ms | 72.527 ms |
| bm_tracker_flat | 29.351 ms | 48.892 ms | 55.351 ms | 49.793 ms | 88.375 ms | 55.393 ms | 45.917 ms |
| bm_xapian | 59.522 ms | 168.591 ms | 55.750 ms | 83.424 ms | 113.679 ms | 62.803 ms | 127.895 ms |
| release:[1999/01/01 TO 1999/09/30] - 121,587 movies, 2,265 matches | |||||||
| t1 | t2 | t3 | t4 | t5 | t6 | t7 | |
| bm_lucene++ | 543.495 ms | 564.582 ms | 609.045 ms | 519.248 ms | 561.844 ms | 663.549 ms | 590.518 ms |
| bm_sqlite | 165.617 ms | 387.256 ms | 293.285 ms | 335.219 ms | 324.528 ms | 324.022 ms | 371.839 ms |
| bm_sqlite_index | 375.504 ms | 315.671 ms | 321.115 ms | 371.228 ms | 300.951 ms | 344.073 ms | 356.366 ms |
| bm_tracker | - | - | - | - | - | - | - |
| bm_tracker_flat | 241.569 ms | 316.626 ms | 398.308 ms | 349.426 ms | 398.289 ms | 318.078 ms | 363.809 ms |
| bm_xapian | 529.377 ms | 556.989 ms | 577.643 ms | 576.194 ms | 626.388 ms | 545.251 ms | 570.695 ms |
| release=1999/03/31 - 9 movies, 1 matches | |||||||
| t1 | t2 | t3 | t4 | t5 | t6 | t7 | |
| bm_lucene++ | 10.065 ms | 10.068 ms | 9.702 ms | 9.974 ms | 9.837 ms | 9.751 ms | 10.356 ms |
| bm_sqlite | 0.164 ms | 0.165 ms | 0.171 ms | 0.168 ms | 0.167 ms | 0.164 ms | 0.162 ms |
| bm_sqlite_index | 0.171 ms | 0.169 ms | 0.171 ms | 0.172 ms | 0.175 ms | 0.165 ms | 0.164 ms |
| bm_tracker | 0.659 ms | 0.476 ms | 0.473 ms | 0.469 ms | 0.464 ms | 0.468 ms | 0.468 ms |
| bm_tracker_flat | 0.510 ms | 0.395 ms | 0.385 ms | 0.384 ms | 0.389 ms | 0.383 ms | 0.389 ms |
| bm_xapian | 0.154 ms | 0.152 ms | 0.151 ms | 0.153 ms | 0.152 ms | 0.156 ms | 0.152 ms |
| release=1999/03/31 - 1,099 movies, 2 matches | |||||||
| t1 | t2 | t3 | t4 | t5 | t6 | t7 | |
| bm_lucene++ | 10.853 ms | 10.545 ms | 10.718 ms | 10.390 ms | 10.521 ms | 10.754 ms | 10.661 ms |
| bm_sqlite | 0.515 ms | 0.528 ms | 0.505 ms | 0.512 ms | 0.502 ms | 0.507 ms | 0.505 ms |
| bm_sqlite_index | 3.139 ms | 0.184 ms | 0.175 ms | 3.440 ms | 0.183 ms | 0.212 ms | 0.205 ms |
| bm_tracker | 4.559 ms | 4.229 ms | 4.177 ms | 4.220 ms | 4.383 ms | 4.532 ms | 4.464 ms |
| bm_tracker_flat | 0.977 ms | 0.830 ms | 0.800 ms | 0.808 ms | 0.802 ms | 0.811 ms | 0.802 ms |
| bm_xapian | 0.672 ms | 0.685 ms | 0.774 ms | 0.752 ms | 0.916 ms | 1.285 ms | 0.663 ms |
| release=1999/03/31 - 3,216 movies, 2 matches | |||||||
| t1 | t2 | t3 | t4 | t5 | t6 | t7 | |
| bm_lucene++ | 10.799 ms | 10.762 ms | 11.399 ms | 10.676 ms | 10.704 ms | 10.169 ms | 10.325 ms |
| bm_sqlite | 1.912 ms | 1.462 ms | 1.453 ms | 1.163 ms | 1.151 ms | 1.157 ms | 4.858 ms |
| bm_sqlite_index | 0.366 ms | 0.350 ms | 0.355 ms | 1.883 ms | 0.364 ms | 0.345 ms | 0.371 ms |
| bm_tracker | 11.707 ms | 11.548 ms | 11.433 ms | 11.425 ms | 11.465 ms | 11.450 ms | 11.912 ms |
| bm_tracker_flat | 1.661 ms | 1.511 ms | 1.513 ms | 1.714 ms | 1.507 ms | 1.612 ms | 1.510 ms |
| bm_xapian | 1.278 ms | 1.364 ms | 1.359 ms | 1.821 ms | 1.994 ms | 1.429 ms | 3.192 ms |
| release=1999/03/31 - 17,251 movies, 3 matches | |||||||
| t1 | t2 | t3 | t4 | t5 | t6 | t7 | |
| bm_lucene++ | 12.485 ms | 12.281 ms | 12.323 ms | 11.981 ms | 12.137 ms | 11.808 ms | 12.552 ms |
| bm_sqlite | 8.247 ms | 6.259 ms | 6.007 ms | 6.300 ms | 6.125 ms | 5.958 ms | 5.921 ms |
| bm_sqlite_index | 0.379 ms | 0.297 ms | 0.285 ms | 0.284 ms | 0.252 ms | 0.254 ms | 0.251 ms |
| bm_tracker | 61.537 ms | 60.815 ms | 61.014 ms | 60.821 ms | 61.013 ms | 60.850 ms | 60.820 ms |
| bm_tracker_flat | 11.063 ms | 8.021 ms | 8.414 ms | 8.690 ms | 7.798 ms | 7.811 ms | 8.313 ms |
| bm_xapian | 5.545 ms | 4.561 ms | 4.956 ms | 4.388 ms | 4.321 ms | 4.687 ms | 4.396 ms |
| release=1999/03/31 - 121,587 movies, 12 matches | |||||||
| t1 | t2 | t3 | t4 | t5 | t6 | t7 | |
| bm_lucene++ | 14.005 ms | 14.031 ms | 12.792 ms | 14.354 ms | 12.736 ms | 13.862 ms | 13.374 ms |
| bm_sqlite | 64.517 ms | 61.783 ms | 61.669 ms | 62.418 ms | 61.377 ms | 61.326 ms | 62.036 ms |
| bm_sqlite_index | 9.994 ms | 0.403 ms | 0.358 ms | 0.351 ms | 0.368 ms | 0.363 ms | 3.368 ms |
| bm_tracker | - | - | - | - | - | - | - |
| bm_tracker_flat | 62.160 ms | 62.760 ms | 56.630 ms | 60.929 ms | 54.310 ms | 53.189 ms | 58.016 ms |
| bm_xapian | 29.180 ms | 28.239 ms | 28.080 ms | 28.054 ms | 27.777 ms | 27.615 ms | 27.505 ms |
| title=The Matrix - 9 movies, 1 matches | |||||||
| t1 | t2 | t3 | t4 | t5 | t6 | t7 | |
| bm_lucene++ | 9.248 ms | 8.929 ms | 9.139 ms | 9.455 ms | 9.609 ms | 9.128 ms | 9.110 ms |
| bm_sqlite | 0.163 ms | 0.163 ms | 0.163 ms | 0.161 ms | 0.160 ms | 0.163 ms | 0.164 ms |
| bm_sqlite_index | 0.167 ms | 0.165 ms | 0.178 ms | 0.164 ms | 0.164 ms | 0.163 ms | 0.165 ms |
| bm_tracker | 0.733 ms | 0.484 ms | 0.475 ms | 0.478 ms | 0.481 ms | 0.475 ms | 0.476 ms |
| bm_tracker_flat | 0.575 ms | 0.400 ms | 0.380 ms | 0.382 ms | 0.379 ms | 0.387 ms | 0.379 ms |
| bm_xapian | 0.226 ms | 0.197 ms | 0.194 ms | 0.191 ms | 0.191 ms | 0.194 ms | 0.190 ms |
| title=The Matrix - 1,099 movies, 1 matches | |||||||
| t1 | t2 | t3 | t4 | t5 | t6 | t7 | |
| bm_lucene++ | 10.758 ms | 10.578 ms | 10.083 ms | 10.230 ms | 10.555 ms | 10.630 ms | 10.831 ms |
| bm_sqlite | 0.728 ms | 0.524 ms | 0.504 ms | 0.501 ms | 0.506 ms | 0.500 ms | 0.501 ms |
| bm_sqlite_index | 0.218 ms | 0.203 ms | 0.201 ms | 0.198 ms | 0.199 ms | 0.277 ms | 0.233 ms |
| bm_tracker | 5.906 ms | 5.409 ms | 5.426 ms | 5.453 ms | 5.420 ms | 5.410 ms | 5.344 ms |
| bm_tracker_flat | 1.685 ms | 1.471 ms | 1.455 ms | 1.455 ms | 1.440 ms | 1.448 ms | 1.439 ms |
| bm_xapian | 0.445 ms | 0.385 ms | 0.398 ms | 0.373 ms | 0.836 ms | 0.451 ms | 0.374 ms |
| title=The Matrix - 3,216 movies, 1 matches | |||||||
| t1 | t2 | t3 | t4 | t5 | t6 | t7 | |
| bm_lucene++ | 10.138 ms | 10.144 ms | 10.652 ms | 10.124 ms | 10.169 ms | 10.070 ms | 10.547 ms |
| bm_sqlite | 2.587 ms | 1.180 ms | 1.198 ms | 2.202 ms | 1.411 ms | 1.422 ms | 1.288 ms |
| bm_sqlite_index | 0.323 ms | 0.300 ms | 0.306 ms | 0.298 ms | 0.493 ms | 0.304 ms | 0.304 ms |
| bm_tracker | 15.097 ms | 14.727 ms | 14.692 ms | 14.759 ms | 14.840 ms | 14.888 ms | 14.791 ms |
| bm_tracker_flat | 3.727 ms | 3.529 ms | 3.558 ms | 3.545 ms | 3.504 ms | 3.504 ms | 3.520 ms |
| bm_xapian | 0.432 ms | 0.353 ms | 0.345 ms | 0.349 ms | 0.348 ms | 0.342 ms | 0.692 ms |
| title=The Matrix - 17,251 movies, 1 matches | |||||||
| t1 | t2 | t3 | t4 | t5 | t6 | t7 | |
| bm_lucene++ | 12.462 ms | 11.871 ms | 12.020 ms | 11.603 ms | 12.469 ms | 11.850 ms | 11.823 ms |
| bm_sqlite | 6.093 ms | 6.096 ms | 6.130 ms | 5.941 ms | 5.882 ms | 5.959 ms | 6.789 ms |
| bm_sqlite_index | 1.431 ms | 0.304 ms | 0.201 ms | 0.200 ms | 0.201 ms | 0.199 ms | 0.199 ms |
| bm_tracker | 79.019 ms | 78.831 ms | 78.514 ms | 78.491 ms | 79.423 ms | 78.506 ms | 78.759 ms |
| bm_tracker_flat | 19.173 ms | 20.160 ms | 19.373 ms | 19.043 ms | 18.992 ms | 18.961 ms | 19.207 ms |
| bm_xapian | 0.422 ms | 0.344 ms | 0.339 ms | 0.335 ms | 0.336 ms | 0.339 ms | 0.345 ms |
| title=The Matrix - 121,587 movies, 1 matches | |||||||
| t1 | t2 | t3 | t4 | t5 | t6 | t7 | |
| bm_lucene++ | 13.367 ms | 13.395 ms | 12.906 ms | 13.164 ms | 12.856 ms | 13.348 ms | 12.862 ms |
| bm_sqlite | 62.625 ms | 61.341 ms | 61.296 ms | 61.361 ms | 61.248 ms | 61.195 ms | 61.607 ms |
| bm_sqlite_index | 0.328 ms | 0.312 ms | 0.300 ms | 0.303 ms | 0.301 ms | 7.473 ms | 0.330 ms |
| bm_tracker | - | - | - | - | - | - | - |
| bm_tracker_flat | 138.148 ms | 131.762 ms | 130.937 ms | 131.431 ms | 131.471 ms | 130.975 ms | 130.770 ms |
| bm_xapian | 0.833 ms | 0.681 ms | 0.674 ms | 0.687 ms | 0.665 ms | 0.667 ms | 0.665 ms |
| director=Quentin Tarantino - 9 movies, 1 matches | |||||||
| t1 | t2 | t3 | t4 | t5 | t6 | t7 | |
| bm_lucene++ | 9.112 ms | 9.540 ms | 9.671 ms | 9.258 ms | 9.510 ms | 9.597 ms | 9.126 ms |
| bm_sqlite | 0.273 ms | 0.243 ms | 0.243 ms | 0.241 ms | 0.239 ms | 0.239 ms | 0.239 ms |
| bm_sqlite_index | 0.282 ms | 0.243 ms | 0.257 ms | 0.244 ms | 0.245 ms | 0.243 ms | 0.337 ms |
| bm_tracker | 0.810 ms | 0.547 ms | 0.542 ms | 0.544 ms | 0.541 ms | 0.554 ms | 0.567 ms |
| bm_tracker_flat | 0.606 ms | 0.410 ms | 0.398 ms | 0.403 ms | 0.383 ms | 0.459 ms | 0.392 ms |
| bm_xapian | 0.215 ms | 0.204 ms | 0.195 ms | 0.197 ms | 0.195 ms | 0.208 ms | 0.194 ms |
| director=Quentin Tarantino - 1,099 movies, 9 matches | |||||||
| t1 | t2 | t3 | t4 | t5 | t6 | t7 | |
| bm_lucene++ | 11.574 ms | 12.063 ms | 11.780 ms | 12.169 ms | 12.253 ms | 11.801 ms | 11.939 ms |
| bm_sqlite | 13.775 ms | 8.831 ms | 9.583 ms | 9.506 ms | 9.193 ms | 9.154 ms | 9.452 ms |
| bm_sqlite_index | 13.332 ms | 8.963 ms | 10.201 ms | 9.064 ms | 8.925 ms | 10.095 ms | 8.756 ms |
| bm_tracker | 5.173 ms | 4.644 ms | 4.546 ms | 4.473 ms | 4.552 ms | 4.472 ms | 4.455 ms |
| bm_tracker_flat | 1.137 ms | 0.857 ms | 0.851 ms | 0.855 ms | 0.844 ms | 0.842 ms | 0.844 ms |
| bm_xapian | 0.898 ms | 0.878 ms | 0.893 ms | 0.873 ms | 1.000 ms | 0.882 ms | 0.843 ms |
| director=Quentin Tarantino - 3,216 movies, 10 matches | |||||||
| t1 | t2 | t3 | t4 | t5 | t6 | t7 | |
| bm_lucene++ | 12.343 ms | 12.175 ms | 12.307 ms | 12.004 ms | 12.235 ms | 12.947 ms | 12.194 ms |
| bm_sqlite | 40.967 ms | 37.867 ms | 38.607 ms | 37.618 ms | 37.487 ms | 37.124 ms | 38.147 ms |
| bm_sqlite_index | 43.470 ms | 36.820 ms | 37.027 ms | 36.779 ms | 36.957 ms | 36.585 ms | 36.782 ms |
| bm_tracker | 13.707 ms | 13.074 ms | 12.763 ms | 12.740 ms | 12.848 ms | 12.779 ms | 12.855 ms |
| bm_tracker_flat | 2.015 ms | 1.559 ms | 1.531 ms | 1.525 ms | 1.530 ms | 1.545 ms | 1.511 ms |
| bm_xapian | 0.933 ms | 0.886 ms | 0.908 ms | 2.944 ms | 1.023 ms | 1.030 ms | 0.799 ms |
| director=Quentin Tarantino - 17,251 movies, 13 matches | |||||||
| t1 | t2 | t3 | t4 | t5 | t6 | t7 | |
| bm_lucene++ | 13.704 ms | 14.413 ms | 14.331 ms | 15.096 ms | 14.026 ms | 14.492 ms | 14.205 ms |
| bm_sqlite | 307.961 ms | 308.146 ms | 308.565 ms | 307.942 ms | 308.342 ms | 308.387 ms | 308.991 ms |
| bm_sqlite_index | 308.011 ms | 305.433 ms | 305.347 ms | 304.567 ms | 304.920 ms | 305.567 ms | 304.404 ms |
| bm_tracker | 72.690 ms | 72.075 ms | 72.005 ms | 71.999 ms | 71.938 ms | 71.946 ms | 72.108 ms |
| bm_tracker_flat | 7.489 ms | 6.996 ms | 6.877 ms | 6.987 ms | 7.148 ms | 7.088 ms | 7.021 ms |
| bm_xapian | 1.087 ms | 0.963 ms | 1.010 ms | 1.151 ms | 1.088 ms | 0.965 ms | 0.959 ms |
| director=Quentin Tarantino - 121,587 movies, 14 matches | |||||||
| t1 | t2 | t3 | t4 | t5 | t6 | t7 | |
| bm_lucene++ | 13.546 ms | 13.955 ms | 13.981 ms | 13.854 ms | 13.740 ms | 14.114 ms | 15.816 ms |
| bm_sqlite | 4,752.853 ms | 2,793.690 ms | 2,800.197 ms | 2,795.611 ms | 2,800.578 ms | 2,794.765 ms | 2,801.000 ms |
| bm_sqlite_index | 2,806.890 ms | 2,789.648 ms | 2,788.729 ms | 2,791.168 ms | 2,788.102 ms | 2,790.845 ms | 2,789.475 ms |
| bm_tracker | - | - | - | - | - | - | - |
| bm_tracker_flat | 47.801 ms | 46.303 ms | 46.701 ms | 46.640 ms | 46.467 ms | 46.862 ms | 46.448 ms |
| bm_xapian | 20.098 ms | 1.260 ms | 1.176 ms | 1.162 ms | 1.156 ms | 1.149 ms | 1.148 ms |
| T* - 9 movies, 9 matches | |||||||
| t1 | t2 | t3 | t4 | t5 | t6 | t7 | |
| bm_lucene++ | 17.303 ms | 17.072 ms | 16.927 ms | 16.539 ms | 16.816 ms | 16.758 ms | 16.797 ms |
| bm_sqlite | 0.547 ms | 0.544 ms | 0.547 ms | 0.541 ms | 0.541 ms | 0.546 ms | 0.544 ms |
| bm_sqlite_index | 0.553 ms | 0.549 ms | 0.554 ms | 0.553 ms | 0.658 ms | 0.547 ms | 0.544 ms |
| bm_tracker | - | - | - | - | - | - | - |
| bm_tracker_flat | 2.525 ms | 2.302 ms | 2.423 ms | 2.415 ms | 2.372 ms | 2.356 ms | 2.305 ms |
| bm_xapian | 3.086 ms | 2.871 ms | 2.947 ms | 2.893 ms | 3.104 ms | 3.022 ms | 3.126 ms |
| T* - 1,099 movies, 1,098 matches | |||||||
| t1 | t2 | t3 | t4 | t5 | t6 | t7 | |
| bm_lucene++ | 358.775 ms | 355.830 ms | 350.287 ms | 349.816 ms | 347.998 ms | 356.585 ms | 347.143 ms |
| bm_sqlite | 64.679 ms | 142.927 ms | 143.776 ms | 142.847 ms | 145.319 ms | 147.244 ms | 135.600 ms |
| bm_sqlite_index | 62.383 ms | 151.941 ms | 144.456 ms | 144.108 ms | 141.330 ms | 173.728 ms | 169.799 ms |
| bm_tracker | - | - | - | - | - | - | - |
| bm_tracker_flat | 199.108 ms | 213.355 ms | 202.793 ms | 196.659 ms | 194.937 ms | 194.708 ms | 195.267 ms |
| bm_xapian | 419.323 ms | 516.929 ms | 677.357 ms | 591.280 ms | 599.091 ms | 643.124 ms | 497.649 ms |
| T* - 3,216 movies, 3,204 matches | |||||||
| t1 | t2 | t3 | t4 | t5 | t6 | t7 | |
| bm_lucene++ | 842.413 ms | 968.828 ms | 958.367 ms | 1,002.383 ms | 932.222 ms | 946.388 ms | 1,004.821 ms |
| bm_sqlite | 327.669 ms | 415.921 ms | 440.198 ms | 408.543 ms | 432.575 ms | 537.572 ms | 412.061 ms |
| bm_sqlite_index | 310.218 ms | 432.201 ms | 413.221 ms | 404.165 ms | 479.691 ms | 431.758 ms | 436.533 ms |
| bm_tracker | - | - | - | - | - | - | - |
| bm_tracker_flat | 727.867 ms | 711.970 ms | 722.046 ms | 717.685 ms | 719.927 ms | 713.077 ms | 713.843 ms |
| bm_xapian | 1,442.238 ms | 1,470.821 ms | 1,415.183 ms | 1,392.164 ms | 1,437.493 ms | 1,464.149 ms | 1,520.747 ms |
| T* - 17,251 movies, ≥ 10,000 matches | |||||||
| t1 | t2 | t3 | t4 | t5 | t6 | t7 | |
| bm_lucene++ | 3,006.139 ms | 3,127.174 ms | 3,136.617 ms | 3,151.197 ms | 3,131.469 ms | 3,141.155 ms | 3,056.497 ms |
| bm_sqlite | 1,481.321 ms | 1,388.573 ms | 1,468.062 ms | 1,533.263 ms | 1,422.012 ms | 1,442.638 ms | 1,456.166 ms |
| bm_sqlite_index | 1,346.717 ms | 1,451.410 ms | 1,508.228 ms | 1,411.643 ms | 1,460.563 ms | 1,514.390 ms | 1,391.342 ms |
| bm_tracker | - | - | - | - | - | - | - |
| bm_tracker_flat | 2,945.536 ms | 2,938.230 ms | 2,957.149 ms | 2,959.569 ms | 2,972.291 ms | 2,933.668 ms | 2,936.655 ms |
| bm_xapian | 3,391.825 ms | 3,490.307 ms | 3,474.203 ms | 3,483.310 ms | 3,560.886 ms | 3,505.060 ms | 3,398.937 ms |
| T* - 121,587 movies, ≥ 10,000 matches | |||||||
| t1 | t2 | t3 | t4 | t5 | t6 | t7 | |
| bm_lucene++ | 3,627.408 ms | 3,625.588 ms | 3,546.610 ms | 3,508.233 ms | 3,599.160 ms | 4,597.857 ms | 4,101.686 ms |
| bm_sqlite | 2,182.548 ms | 2,109.730 ms | 2,109.812 ms | 2,121.573 ms | 2,104.320 ms | 2,117.912 ms | 2,145.342 ms |
| bm_sqlite_index | 2,108.863 ms | 2,103.648 ms | 2,131.009 ms | 2,132.823 ms | 2,109.655 ms | 2,137.286 ms | 2,106.779 ms |
| bm_tracker | - | - | - | - | - | - | - |
| bm_tracker_flat | 8,757.130 ms | 9,316.640 ms | 8,708.298 ms | 8,781.584 ms | 8,788.042 ms | 8,699.770 ms | 8,721.099 ms |
| bm_xapian | 4,805.474 ms | 4,528.004 ms | 4,692.763 ms | 4,640.065 ms | 4,618.215 ms | 4,647.170 ms | 4,674.588 ms |
Ever since the announcement of the N9′s DLNA support people were looking for a feature called DLNA +PU+ which allows you to send media files to e.g. DLNA-capable TVs without enabling content sharing on your device, giving you a really fine-grained control about what and where to share to.
PushUp is a small utility that hooks into the N9′s sharing framework and allows to you push an image or a video to your TV just like you would with Bluetooth or NFC. Get it on this site (or later through the Nokia Store).
It is an offspring of my Korva project, a D-Bus specification and its implementation for media pushing. While still work-in-progress, it’s already fully functional.
Edit: I had to update the package because the icon was missing and cancelling the device selector was broken.
Edit2: Updated again since it was broken on PR < 1.2.
Today I deployed the latest Online Glom (gwt-glom) on a new Amazon AWS instance of Ubuntu Precise, again connecting Apache with Tomcat. This time I took notes about exactly how I did it. I wonder if this is something that I should put in a Puppet configuration (I have never used Puppet).
It took me a while to figure this out last time, but now it’s clearer to me. However, I still don’t know how to avoid the need for the /OnlineGlom/ suffix in the URL.
Over the last few weeks, in occasional spare moments, I have added report generation to Online Glom. It kind of works now, using the regular report definitions from the existing .glom files, and generating reports that look much like the reports in the desktop Glom version. I deployed this at onlineglom.openismus.com/OnlineGlom/ .
I used JasperReports for this, writing some code to map Glom’s report structure to the JasperReports structure. I chose JasperReports mostly based on its popularity. There are various tools and libraries that use it and the JasperSoft company seems to be very successful by supporting it.
However, I will probably replace JasperReports with some custom code instead, because:
- The JasperReports API is almost completely undocumented. I figured out what to do only by looking at various snippets of code from random places. The project seems to focus on the use of visual tools to build report designs, rather than the use of a generic API by such tools.
- JasperReports demands absolute positioning, with no automatic layout, and that will never make sense for HTML.
I will try the DynamicJasper wrapper/helper before abandoning JasperReports, but I don’t see how it can avoid the fundamental problem of absolute positioning.
Openismus asked me to research how best to index media files and provide full text searching. For the last two years, I have used Tracker for this kind of thing. I like Tracker, but I want to avoid being biased. Therefore, I decided to evaluate alternatives.
Performance is an obvious requirement. We also want to provide a library to permit other applications to access the data we collected. Therefore, SQLite and Lucene (in its C++ incarnations) are obvious contenders. Lucene++ is an emerging project that got suggested by Mikkel Kamstrup Erlandsen at Canonical. QtCLucene is a bit special: So far Qt doesn't provide official support for this library and doesn't install its headers files. Still it is used by Qt's help system, which makes QtCLucene a widely deployed and well tested C++ implementation of Lucene.
Sadly, the big names like MySQL or PostgreSQL do not fit: MySQL's embedded server library is licensed under GPL (instead of LGPL, for instance), which greatly limits legal use cases. PostgreSQL doesn't provide any embedding at all. Because I enjoy RDF and SPARQL I also wondered about testing the Redland RDF libraries, but I found that they don't provide any full text search at all.
Contenders
- Tracker 0.14.0-2ubuntu1
- SQLite 3.7.9-2ubuntu1
- Lucene++ 3.0.3.4 (e28b15b02ff9de2208965e9af8eb80983380cdcd)
- QtCLucene as provided by libqtcore4 4.8.1-0ubuntu4
- Xapian 1.2.8-1
Test Platform
- Ubuntu 12.04
- Intel Core 2 Duo P8400 (2.26GHz), 4 GiB RAM
- HDD: WDC WD2500BEVT-2, encrypted (aes-cbc-essiv:sha256)
Test Scenario
To get somewhat realistic data I've fetched a copy of the Internet Movie Database from ftp.fu-berlin.de. Since it is a quite huge database (about 1 GiB when compressed with gzip) I've extracted a few subsets of it: All movies with at least 500,000, 50,000, 15,000 1,000 and 50 user votes. This data then got imported into a fresh instance of Tracker, SQLite, Lucene++ and QtCLucene. After that I've run a few trivial full text searches:
"The Matrix"
Fast Furious
"Star Trek" OR "Star Wars"
Lord Rings King
Keanu Reeves
"Brad Pitt" OR "Bruce Willis"
Jackson Samuel
Quentin Tarantino
Wachowski
Thomas Neo Anderson
Neo
Each scenario was repeated five times. To avoid cache effects each engine was tested after the others for a given set of parameters. Tracker was tested with two different scenarios: First I've tried the Nepomuk based multimedia ontology shipped with Tracker (nmm), after that I've also tried a flattened ontology (fmm) which is a much better fit for the data model of pure full text search indices like Lucene. All engines where used with default parameters. No magic configuration options or pragmas were applied. Feel free to repeat the tests with your own optimized settings, and report the results when doing so.
Source Code and Data
The source code of these benchmarks can be found at Gitorious, and can be built using autotools or qmake. Just like you prefer.
Run src/benchmark.sh to reproduce the tests. The log files can be turned into a CSV file by running src/report.sh.
The charts have been created with LibreOffice:
It should be sufficient to copy the CSV data into the data sheet of
logs/report.ods.
Select "English (USA)" as language in the import dialog, to ensure that
numbers are recognized properly. After that you still might have to sort
the rows by the columns suite, num_movies and experiment. The data
sorting dialog provides an option for marking the first row as column header.
Update: I've pushed some more changes, so to exactly reproduce the results
discussed in this post, checkout the tags releases/0.1 for the
initial results, and releases/0.2 to also include Xapian tests.
Results

| Lucene++ | QtCLucene | SQLite | Tracker (Nepomuk) | Tracker (Flat) | Xapian | |
|---|---|---|---|---|---|---|
| 9 | 6.84 ms | 3.46 ms | 43.2 ms¹⁾ | 36.2 ms | 7.13 ms | 52.561 ms¹⁾ |
| 1,099 | 2.93 ms | 5.72 ms | 3.63 ms | 26.4 ms | 3.32 ms | 5.94 ms |
| 3,216 | 2.32 ms | 5.37 ms | 2.87 ms | 21.2 ms | 2.89 ms | 4.97 ms |
| 17,251 | 1.98 ms | 5.10 ms | 2.50 ms | 14.2 ms | 2.19 ms | 3.58 ms |
| 121,587 | 1.21 ms | 5.21 ms | 3.96 ms²⁾ | 10.4 ms | 1.80 ms | 2.30 ms |
- The dataset is tiny. I suspect that some startup overhead is invalidating this result.
- We might see first signs of a memory barrier here.

| Lucene++ | QtCLucene | SQLite | Tracker (Nepomuk) | Tracker (Flat) | Xapian | |
|---|---|---|---|---|---|---|
| 9 | 2.23 ms | 0.572 ms | 0.159 ms | 1.33 ms | 0.494 ms | 0.271 ms |
| 1,099 | 6.06 ms | 2.18 ms | 1.17 ms | 90.3 ms | 1.67 ms | 0.955 ms |
| 3,216 | 8.72 ms | 3.41 ms | 1.55 ms | 335 ms | 3.57 ms | 1.50 ms |
| 17,251 | 13.1 ms | 5.33 ms | 1.92 ms | 2,380 ms | 7.52 ms | 2.35 ms |
| 121,587 | 17.0 ms | 44.2 ms | 17.4 ms | 86,800 ms | 19.885 ms | 18.1 ms |
| Complexity | O(log(n)²) | O(log(n)²) | O(log(n)²) | O(n log(n)) | O(sqrt(n)) |
QtCLucene, SQLite, Tracker (Nepomuk) and Xapian seem to hit a memory barrier at 121,587 movies.

| Lucene++ | QtCLucene | SQLite | Tracker (Nepomuk) | Tracker (Flat) | Xapian | Raw Data | |
|---|---|---|---|---|---|---|---|
| 9 | 80 KiB | 76 KiB | 368 KiB | 4.4 MiB | 2.3 MiB | 424 KiB | 104 KiB |
| 1,099 | 4.9 MiB | 4.8 MiB | 32 MiB | 59 MiB | 29 MiB | 21 MiB | 7.8 MiB |
| 3,216 | 12 MiB | 12 MiB | 75 MiB | 114 MiB | 53 MiB | 47 MiB | 18 MiB |
| 17,251 | 39 MiB | 39 MiB | 257 MiB | 305 MiB | 155 MiB | 170 MiB | 57 MiB |
| 121,587 | 154 MiB | 154 MiB | 1.0 GiB | 906 MiB | 521 MiB | 683 MiB | 198 MiB |
Discussion
The performance of Tracker is devastating. Entirely not the result you want to see for a project you actually like and enjoy using. You clearly see the bad impact of the many joins it must perform for mapping the ontologies and queries to SQL. This is surprising since in my opinion Nepomuk's multimedia ontology is a quite typical ontology. Also the datasets itself are not that huge for something that initially started as file indexer. The (sadly quite unrealistic) flat ontology might give a few hints on how to improve Tracker. The execution times with this ontology are comparable with them of the other engines. Still the observed (and only estimated) complexity class for executing queries is worrying.
Lucene++ shines at writing data, it is just incredibly fast when building its index. In contrast to the other engines it even spends less time per movie, the bigger its index grows. It is noticable slower than QtCLucene or SQLite when looking up terms. Still I'd call an average time of 17 ms for finding matches within 122k documents a quite good achievement. Additionally Lucene++ seems to be implemented sufficiently efficient to not hit any memory barrier yet at this scale.
QtCLucene is about two times slower than Lucene++ or SQLite when building its index, still the index size doesn't seem to impact insertion time per movie. It pays back with good lookup performance. It is about 2 to 3 times faster than Lucene++. It seems to hit a memory barrier at 122k documents.
SQLite's performance is just in the middle between Lucene++ and QtCLucene when building the index. When searching terms it even beats QtCLucene, again by a factor of 2 to 3.
Lucene++ and QtCLucene consume less disk space than the original files, most probably because the raw data stores movies and artists in separate files. The records in this files must be linked with each other. Lucene just does this more efficiently. SQLite and Tracker consume significantly more disk space than Lucene or the original data. Partly this can be explained by fields being stored twice: Once in their table and another time in the full text search index. Column indexes also play a role. Still this doesn't explain why disk consumption is significantly higher.
Xapian's characteristics are quite similar to those of SQLite. It doesn't hit yet that memory barrier that affects SQLite's insert performance at 122k documents, maybe because it consumes only 2/3 of the disk space. Enjoyed its API for being much closer to modern C++ than any other engine. It gives more low-level access to all the FTS mechanics: For instance you have to attach values and feed the indexer yourself. Also you have to deal with token prefixes. Details that Lucene just hides behind a Field class and its attributes. Not sure yet, what approach I prefer.
Conclusion
Tracker is out. Lucene++, QtCLucene and SQLite are quite comparable in terms of performance, with Lucene++ being the fastest engine when building the index, and with SQLite being the fastest when performing full text searches. There are some first signs that Lucene++ is more memory efficient than its competitors. This needs further investigation. Also we should investigate capabilities for doing point and range searches, instead of full text searches.
I released stable Glom 1.22.0 a few days ago.
For easy installing, I also created a Glom 1.22 package for Ubuntu Precise, in the Openismus PPA. Ubuntu Precise normally has Glom 1.20. I wish there was some similar way to create packages for Fedora, or someone to do that for me.
Beside the multiple bug fixes, Glom 1.22 has a few new features:
- Details: Foreign key ID fields: Add a New button next to the existing Find button.
- Allow custom (not related) choices to be translated, with only the original text being stored in the database. This only happens when the choices are restricted, at least for now.
- Related Choices: Default to showing the primary key but allow the field to be be other than the primary key.
- Related Choices: Allow the user to specify a sort order.
- Allow the database title to be translated.
- Added command-line utilities to help with translation via po files.
For some reason I’ve a notebook with a Swedish keyboard but when docked I use my ergonomic keyboard with a German layout. To automatically switch the layout when the external keyboard is connected, I cooked up this script and added a .desktop file to $HOME/.config/autostart:
#!/usr/bin/env python from gi.repository import Gtk, GLib, Gkbd import usb import sys # Holtek Semiconductor, Inc. PS/2 keyboard + mouse controller vendor=0x04d9 product=0x1400 c = Gkbd.Configuration.get(); try: # find index for german de = c.get_short_group_names().index('de') for bus in usb.busses(): for dev in bus.devices: if dev.idVendor == vendor and dev.idProduct == product: c.lock_group (de) sys.exit(0) except Exception, e: print e pass
This is using pyusb 0.4, it gets a bit easier with 1.0.
TL;DR: First release of Helium! Please try it out and reports issues at https://github.com/phako/Helium/issues or as a comment if you don’t want to register with github,
The first installable version of Helium is out. Grab the debian package for your N9 here. As usual it’s signed with my public key 6BA1DF74.
This version is not submitted to the store (yet) since I felt it needs a bit more testing, especially on the interaction with media renderers. I’ve only two renderers that are not Rygel-based and one of them is severely broken when it comes to UPnP.
So please, try it out and report any issue you find either via its issue tracker at github or as a comment here.
Basic usage instructions are available on this site.
This is a feature that I personally wanted for a long time. Interrupted by FOSDEM, some Wayland research and many other things, I finally managed to get word prediction and error correction beyond prototype quality. The video shows just how amazingly good the Presage word prediction can be, even without extensive training (in fact, for the video we used the minimal language model training that comes with a regular Presage installation). The second part of the video shows how combining Presage with a spellchecker such as Hunspell further improves the provided word candidates.
Presage uses a very scalable approach called text n-grams. There is a lot of research in that area, but language models of contemporary language usage are either well guarded or cannot be freely distributed. Luckily, Presage comes with training tools such as text2ngram. Users can feed arbitrary language corpora to it, though one should be careful to perhaps not mix different languages too much.
Matteo Vescovi, the author of Presage (formerly known as Soothsayer), started the work as part of his master thesis a couple of years ago. The heart of Presage are the different predictors. They can be queried in parallel and the result lists are merged, using probability analysis.
Presage certainly has a lot of potential. It comes with an easy to use C++ API but also provides bindings for C and Python. In fact, it even provides a D-Bus API, which would make it possible to run it as a system service. The user could then benefit from (and train!) the same language models from different applications.
Hunspell probably doesn’t need much introduction. It is used in many Linux desktops. It’s a fine library and comes with many dictionaries. However, one should be aware that Hunspell itself cannot provide word prediction, which is why it wasn’t enough for mobile text input. As a fallback for Presage, it works very well though.
Of course there are a couple of things we could do from here. As Jon mentioned in the video, the virtual keyboard’s word ribbon UI could host word suggestions from other applications, such as the Google search in the browser. For Unity’s dasher input or Gnome Shell’s search, the application names could be shown instead. Or we could hook it up to Bash completion.
PS: Anyone up to package Presage for Fremantle or Nemo? It could be pretty interesting to see the next release of Maliit running on the N900.
I finally decided to watch Hard Candy. The best review I could find still misses to see the elephant in the room.
If you think that the movie didn’t give us enough insight to understand Jeff, the supposed predator, then the simple answer is: You’re not supposed to understand Jeff, unless you are a pedophile. I didn’t understand Jeff either, but he did enough mistakes to reveal himself as dangerous and sick.
So whatever happens to Jeff is, in a way, justified. There’s even that revelation scene where he thanks Haylay, the supposed victim, for showing him what he truly is. Become what you are, as they say.
I imagine Hard Candy to be the ultimate shocker for pedophiles. It should be required viewing, as it would be interesting to see their reactions. I kind of expect that those who fully understand Jeff might reach the same conclusion as he did, or at least feel guilty enough to change. Perhaps that’s the only intention of the movie, as I seriously doubt it was meant to be entertaining. In that sense, Hard Candy is more than a mere exploitation movie and certainly not comparable to torture porn.
I definitely need to watch out for more Ellen Page movies. I did not like her in Juno (probably because I did not like the movie at all), but this time her performance was stunning. Might be that Patrick Wilson acted better (or simply had better scenes; anyone else thinks he and Tom Hardy could be brothers?), but I think it would be unfair to expect a then 17 years old to be an accomplished actress. Although there is the fear that she might already had her best moments. If I think of Inception, her performance was nothing special, sadly.
The standard way of deploying Maliit is to have a single maliit-server instance (per user session), hosting the actual input method (virtual keyboard, handwriting). Applications then communicate with the server (and by extension, the IM) through an IPC.
This allows for a single instance of Maliit to serve all applications, which is memory efficient and robust. A crash in a Maliit IM plugin cannot take down the application and risk loss of significant user data. The disadvantage is the increased system complexity (a separate server process needs to be running at all times*) and requiring compositing of the application and input method windows. The latter can be quite challenging to do in a well-performing way on low-powered mobile/embedded devices. See Jans blogpost for how we handled that on the Nokia N9.
* By default we make use of DBus autostarting, of course.
Application-hosted Maliit
To make Maliit more suitable for systems where only a single application runs (embedded) or compositing performance is not good enough, we now also allow Maliit to be “application-hosted”: the Maliit server and input method plugins lives in the application process, not a separate server process. Enabling this feature has been a long running task of mine: All the code in input-context and server was made transport independent, a direct transport (no IPC) was introduced, and setting up the server for a given configuration (X11, QPA, app-hosted) was simplified. Other motivations for this work include being able to run the server and IM plugin easily for automated end-to-end system or acceptance testing, or just to easily start the server with a given IM plugin loaded for quick manual testing during development (see Michaels merge request).
An example application exists as part of the Maliit SDK that demonstrates the feature: maliit-exampleapp-embedded

Maliit running in application-hosted mode: The Maliit Server and input method plugin is embedded in the application instead of running in a standalone server process.
This works by having a special input-context “MaliitDirect” which instead of connecting to the server over DBus, creates the server and a direct connection. As when running standalone the server will instantiate and manage the necessary input method plug-ins.
Because the IM does not have its own window in this configuration, the application is responsible for retrieving the IM widget from the server, and re-parenting it into the appropriate place in the widget hierarchy. For all other purposes the application uses the same interface as if the IM was hosted remotely, making sure the abstraction is not broken and that one can easily use the application with Maliit deployed in different configuration.
This feature currently works with Qt4 applications, and is in Maliit since the latest release (0.90.0). One issue is that with the current input method API, the plugin assumes a fullscreen window; overlays extending the base area of the IM will be clipped and size needs to be overridden. This is something we are fixing in the new improved API.
Compositor-hosted Maliit
Another approach to make rendering perform better is to host the input method in the process responsible for the compositing. This also reduces the number or processes involved in rendering/compositing, and the associated overhead. This could be a X11 compositing window manager (like KWin or mcompositor), but a more realistic use-case is a Wayland compositor (for instance based on QtCompositor).
The API allows the consumer to inject an class instance for the configuration dependent logic, allowing to integrate the Maliit server with the logic in the rest of the compositor. Applications will use the normal “Maliit” inputcontext and communicate to the server through an IPC like DBus.
After the work with application-hosted Maliit, this feature was completed by making the server and connection libraries available as public API. The API is available in the latest Maliit release (0.90.0), but is considered unstable until Maliit hits the 1.0 mark.
Enabling third-party developers of input methods is one of the primary goals in the Maliit project. In an attempt to improve this story I spent some time on getting Maliit to work on Windows.
Since we use Qt there were few changes needed to the code, but since we use qmake, quite many to the build system. One of the bigger changes was making glib-dbus and qdbus optional, which is also useful for Maliit on embedded systems.
With the Windows build fixes merge requests for maliit-framework and for maliit-plugins, one can now build Maliit on Windows and run the provided example applications. This feature is currently being reviewed and should be in the next Maliit release.
Thanks to the standalone viewer application for Maliit Keyboard this allows one to develop new features, theming and language layouts for it on Windows.
Sadly loading an input method plugin in the maliit server crashes for an unknown reason. With my limited Windows software development experience I was not able to solve this within the couple of days I had available. This is necessary for application-hosted Maliit to work and to enable general development of Maliit input method plugins (not just maliit-keyboard). Help would be much appreciated, even just someone checking if it is reproducible on another Windows system.
Also left on the todo-list due to lack of time is to set up a Windows build slave for the Maliit buildbot, to test that the build continues to work on Windows and to produce executables.
Today I pushed a new version of TweakUp to the Nokia store, fixing a small cosmetic bug and including the translations that have been added on Transifex so far. Thanks to everyone who contributed a translation. Again, for the impatient, the new version is here, alongside with the signature.
I consider comments to be an essential part of the whole blogging experience. Especially when writing less than neutral posts (which I love to do, for various reasons), it is important to get that direct feedback from comments. I want to get to the point where the blog post is perhaps only two-third of the total value, with the remaining third coming from the emerging discussions in the comment section.
But I didn’t like the default settings of Posterous. Every comment needs to be moderated. It effectively kills any discussion attempt. And whenever I moderate (well, is my accept-everything policy so far even moderating?), I feel the strange urge to reply to the comments. Which means I was responsible for half of the comments in my last blog post. I always disliked that when I saw it on other blogs, but now I know why it happens.
So better to just let everything show up instantly, and reserve the right to delete comments (which I think I never did, but that’s of course the blessing of usually only getting very few, or zero, comments).
Not quite. Because I have to think about anonymous posters, too. I feel that keeping the entry barrier for comments as low as possible is a good thing. Captchas are already annoying enough, but I’d be insane to disable them. So allowing anonymous comments is good, right? I no longer know!
After talking to my brother, he said that he would never again allow anonymous comments on his blog, even if he fixed commenting there. So I looked around the web a bit, and searched for anonymous posts on blogs. Instead of contributing to the discussion, they seemingly only add noise and/or are used to insult the blogger. Seems my brother was right about it, once more. But if nothing useful comes out of anonymous comments (unless you consider insults to be valuable feedback), then why have them?
That is why for this blog, I will handle comments without moderation, but delete if absolutely needed. Commenters will have to be logged in with one of the services that have been integrated with the Posterous comment system. Twitter login for example works. I just hope that Posterous stays up for while after the take-over by Twitter, to make all the time I invested in setting up this blogging space worth-while ;–)
Currently TweakUp only speaks English. I’ve modified the source and setup a Transifex instance to change that in a future release. Since the only two languages I can express myself in without sounding too stupid are English and German, my translation skills are a bit limited. So if anyone is interested in contributing a translation, feel free.
Links:
As I mentioned on several places already, due to the aim of getting the N9 DLNA-certified we had to introduce some restrictions. One of the most annoying limitation from an end user point of view is that you can’t share arbitrary videos or music which you may have put on your device. Another, though minor, issue is that it’s not possible to change the name shown in UPnP or DLNA clients on the network.
While it is possible to change all this by editing the configuration file, it is somewhat inconvenient to do this on the device. That’s why I’ve written a small application called TweakUp which allows all these settings (and a few more, see the screenshot) to be changed more comfortably. It is available in the Nokia Store and on this website. It has been signed with my public key 6BA1DF74.
Its source code is available at https://gitorious.org/helium/tweakup
Last week I submitted an application on behalf of the Maliit project to participate in this year’s Google Summer of Code, as a mentoring organization. Today I got the rejection mail in my inbox.
Maybe I am too European to understand this, but what I find disappointing is the lack of any reason given in that e-mail, other than that too many applications were received. I mean, how am I supposed to learn from that? How will I know whether a project like Maliit has any chance at all, or whether I should even try to submit a project next year? Even for the list of accepted organizations, such as KDE or GNOME (of which both are pretty much doing the same stuff, so why do we need both here?) no reasons are given of why they were accepted.
Having had a bad experience with opaque decision making in the MeeGo project, this tastes just as bad. Sure, not giving reasons so that you don’t have to argue about them later on has apparently become a standard procedure, but I am not willing to accept such behaviour. After all, I also spend time in writing the proposal, and I find it disrespectful to only receive an empty, canned response.
If you are on the other side of a similar process, be it for a conference or because you work in the HR department of a company, please do think about whether it’s really too much to ask for the extra five minutes it takes to provide the reasoning behind your decision, and whether you would like to be treated the same way as you treat others.
Google can certainly do less evil than that.
PS: This blog post about the rejected WordPress project mentions a follow-up meeting, but I was unable to find any concrete information on the GSoC website.
PPS: On the list of accepted organizations, you’ll find entries such as “Name: Pidgin, Finch, and libpurple. Tags: pidgin, finch, libpurple, instant messaging, im, networking, gtk, glib, c, amazing, awesome, a+++++ would do business with again, space mice, team edward” (emphasis mine) – is that supposed to be taken seriously? Or shall I conclude that the submissions are not thoroughly reviewed?
Update: There are some who try hard to misread what I wrote. I think I should clarify what a successful application as a GSoC organization means.
You will:
- spend a lot of time mentoring students during your typical holiday and travel season;
not get paid for that(the students will); (update: mentors get 500USD, thanks to lucianafujii for pointing that out)- receive a GSoC T-Shirt;
- be invited to the Googleplex later the year (you will usually have to take extra holiday for that though, so there goes more of your spare time, if you accept the invite);
- increase the visibility of your project.
Heavily simplified, GSoC consists of one entity providing the money, another entity providing time and a third entity consuming both. There’s also a big deal of knowledge transfer happening between the entities, but the flow is less clear than for time and money.
However, my point is: I would have been part of the time spending entity and without that entity, GSoC simply does not happen. So think again before you essentially reduce me to a loudly complaining free-rider who should STFU and get over himself.
Openismus has recently had to let some great developers, and good friends, go. We are now much smaller.
This is really sad because it took us a long time to find and train these people, and they would be massive assets if the future looked better. Although they will be greatly missed, I am at least reassured that they will have no problem finding new jobs. I do hope that they don’t settle for work that is anything but worthy of their experience and enthusiasm.
This downsizing happened because we are now finally losing the customer work we had from Nokia, as expected since their February 11th 2011 decision to kill MeeGo. Nokia are not our only customer, but they are by far our largest. That gave us the opportunity to diversify, and we tried, but without much success. That failure is mine. On the one hand, it’s unfortunate that we have been so dependent on one customer. But, on the other hand, we would never have been so big for so long without them. I would do the same again without regrets.
I view the last few years of Openismus very positively:
- We gave several young developers their first chance to prove themselves as professionals.
- We trained new developers. They are now established as respected and experienced developers.
- We made a few contributions to our favorite projects. For instance, natural layout in GTK+ 3.
Personally, Openismus has allowed me to work part-time, so I can spend time with my children. My first child was born soon after the company was founded, and for the first year, I worked from home, contrary to the myth that founding a company means working all hours of the day and neglecting your family. The tech industry is excessively male, with little understanding for men who want to share in the work of child-rearing, so I’m glad I had the freedom to work part-time. I am highly motivated to keep this freedom.
This has been a disadvantage, of course. For instance, I strongly suspect that I could win more customer work by traveling more to conferences and to customers on site. That has given good results when I’ve managed to do it. But this is simply an impossibility for someone who needs to take care of kids. I think the custom of business travel might be one of the greatest obstacle to women reaching top executive positions. It’s one of many things that won’t improve until men are forced to share more of the burden.
So, Openismus goes on, with some uncertainty. Our specific expertise in the Maliit input methods, in the QtContacts and EDS contacts systems, and in DLNA via Rygel should be very attractive, but time will tell. If you need help with GTK+ or Qt on Linux, from people who really know how, and are not afraid to tell you how, then we are still here and still ready.
Today we have reached step two of what we aimed for when using Rygel on the N9. This morning I got notified that it has been certified by DLNA as a M-DMS device. After a very long struggle (more than two years) with the sometimes nearly insane requirements DLNA imposes on a project, the weird tooling and the testing process, after all the effort that multiple people have thrown into this goal, by the end of last month, it looked like we were not going to make it. The reasons were very, very stupid and didn’t have to do anything at all with Rygel. Getting the news today was a great relief, a huge reward and a very fitting finish for working on this project.
A big thank you to Zeeshan and all the other people involved in making this happen.
Thanks to Chris we got ourselves a new logo and a new icon, making your favourite media server look even better in your player. It is already on master and will be used in the next stable release.
What’s Helium?
Helium is a UPnP control point that is supposed to accompany Rygel, but can of course work without it. It offers browsing of media servers, selecting a renderer from a list of devices available on the network and can (currently) play back a single media files from the current server listing to the currently selected renderer (by long-push). This is supposed to change in short-term, giving proper playlist and player controls. Also it needs to get aware of servers and renderers disappearing from the network and get some proper error reporting.
Where’s the code?
Current state is available at Gitorious
Screenshots
As mentioned before, Jon and I met with Kristian Høgsberg and Peter Hutterer during FOSDEM 2012. The discussion quickly revolved around Wayland and input methods. Kristian and I basically picked up from where we left after the Qt Contributor Summit last year in Berlin.
Right now, there is no explicit input method support in Wayland, and it’s the responsibility of the applications to provide such. But we came to the conclusion that moving it into Wayland provides several benefits.
That is why I spent some time during February to write down an initial design proposal, using the two years of experience from working in the application framework team for the Nokia N9. It has gotten longer than expected, but hopefully it is structured well enough to still be accessible.
From the introduction:
Currently, Wayland has no explicit text input method support and relies entirely on toolkit-specific or platform-specific solutions. This is awkward for platforms that support multiple toolkits. The resulting fragmentation and re-implementation would make it hard to attract developers of high-quality text input methods. These developers would generally prefer a unified architecture that lets them ignore application-specific or platform-specific details. This would let them simultaneously target all platforms that support Wayland.
We believe this goal can be reached by adding two new Wayland protocols, of which only one requires adaptation by toolkit providers.
The idea is not new, XIM has been around since the dawn of time. Because of the protocol’s daunting complexity, it apparently never became popular among application toolkit providers. That is why I decided to split up the envisioned Wayland input method protocol up into two:
- The Wayland text protocol, to be used between the Wayland compositor and its clients. It tries to keep input method knowledge to a minimum and therefore can be used for any kind of (hardware) input that results in text input.
- The Wayland input method protocol, to be used between the Wayland compositor and the input method system, which can either run as a stand-alone process or inside the compositor process.
In the proposal, I explain my ideal solution where applications and input method system are completely separated from each other and where the compositor acts as a mediator between them. I continue with alternative solutions that are feasible but have several drawbacks. Towards the end, there is a comparison matrix that features all discussed solutions.
There is an important aspect though: The alternative solutions provide an iterative implementation approach to reach the ideal solution. The obvious idea here is that already in early stages, we get testable prototypes. The solutions with a compositor-hosted input method system for instance allow others to think about window management policies that take input methods into account, whereas I could continue my iterations towards the ideal solution.
Anyhow, the next steps are now to discuss the proposal in a wider public (feedback from developers of exotic input methods especially welcome!), possibly also at upcoming conferences, and to come up with a prototype implementation so that we can iron out protocol bugs.
I would probably target Qt 5 as the first application toolkit to support the Wayland text protocol, followed by GTK+ and perhaps Enlightment. One also needs to take the popular desktop shells into account, such as Gnome Shell, Unity and Plasma Active.
Maliit could fill the role of a reference input method system, but we should have at least one more implementation, at some stage (IBus comes to mind, naturally).
Looks as if this could keep me busy for the better part of 2012, but it would be great if we could get at least the Wayland text protocol into Wayland 1.0. It’ll require some luck though.
There is seemingly a trend (in ideas) to use your mobile device as a remote control for stationary devices such as your TV.
We thought that experimental support for remote text input should be easy to add to Maliit, as it already comes with a server-client architecture. As soon as client and server can run on different host machines, we’d have network transparency and it should basically just work. Luckily, we use D-Bus as our IPC, and it turns out that D-Bus understands remote host addresses. If you check the README in maliit-framework you will recognize that – with the latest release (0.90.0) – it only takes an additional environment variable, MALIIT_SERVER_ADDRESS, to connect a client (that is, an application that uses the Maliit input context) to the input method server. The scary part is perhaps that one has to disable D-Bus authentication. Therefore it's a good idea to only use this inside a trusted network.
Jon created a video which demonstrates the new feature in a better way, using a laptop that is connected to a projector as a TV replacement. The great thing about this feature is that it requires no changes to the applications, nor to the Maliit input method plug-ins, it’s the framework that handles this internally (or not so internally, now that Qt 5 turned our D-Bus API into a public one).
However, to make Maliit truly useful as a remote control, at least two additional features are required:
- Have a proxy text editor widget on mobile device that allows text interactions such as copy and paste, cursor positioning and rich text formatting.
- Emulate and transmit mouse or touch events, possibly through a dedicated touch area on the touch screen of the mobile device.
The second feature requires an extension to the Maliit protocol, whereas the first is already filed as bug MALIIT#84. After that, I could use my N9 (or my N900, as Maliit also runs there) to remote control my Gnome or Ubuntu Unity desktop, which would work perfectly for my movie watching habits. Kudos goes to Krzesimir and Jon for their work on this feature.
Switching the tool for exactly the same work is the stuff I absolutely try to avoid, but it seems that maintaining your own blog software, even if for the right reasons, is still the wrong thing to do. I want to focus on writing my thoughts down, and solutions for that exists.
Yes, your hosted blog solution may get hacked, it will get owned, the provider will go bust. It’ll all happen, eventually. And then it’ll be too late to think about exporting your data, or backups. But they come with many time saving features, so that if we compare the amortized costs, the ready-made solution might still win. Let’s see how well it goes with Posterous, it seems to have all the features I need (I can even send my blog posts via e-mail). Wordpress might have been the obvious candidate, but it also attracts all the script kiddies these days. Too big for its own good, one might say.
Importing my blog posts
For importing my blog contents, I briefly checked the provided API, but then did something that will earn me no respect among my colleagues: I did the import manually and chose to ignore comments completely. Here’s why: I figured out that each post will take me less than 2min, and I had some 60 blog posts to import. So the expected import time was 2h, and even with a Scotty factor of 1.5, this still seemed faster than trying to write an import script, or an import mailer. I don’t expect to have to do this very often, and even if I had to do this once every year, it would probably still cost me less than a day, sadly (read: not worth it to write a script).
The most important aspect though: There’s uncertainty in any kind of software development and the manual blog post import had already proven itself to just work. I am a risk-aversive rational person in general, so the choice, for me, was obvious. This also shows that I derive little motivation from writing software as such; I need to be convinced by the utility new software provides, or that it at least improves efficiency.
Sometimes I wish I could just switch off my rationality though, and enjoy hacking more.
The remaining bit is to redirect the RSS feeds, hoping that the planets will deal with the old posts correctly and have a heuristic that takes the post’s date into account.
Over the last few months I have developed the habit of writing tests when fixing bugs in Glom. These run during “make check” or “make distcheck” so I can be sure that the bugs have not come back. (I know these tests should be smaller and even more numerous, but I can’t yet see a sensible way to break them up).
I had to do lots of build-system and code work to make this possible, because some code had to be moved out of the UI code, and many tests depend on a temporary local server instance. But now, it’s easy to add new tests and it feels so good.
When the tests succeed I have a feeling of confidence in the code, instead of a feeling of uncertainty. When they fail I feel glad that I had a chance to fix a regression before releasing a new version. I am surprised at how much more enjoyable this has made coding.
It looks like the PR1.2 update for the N9 is starting to get rolled out now, so your favourite MediaServer implementation will reach your phone soon.
A short hint if you’re eager to try it and you don’t see any files shared: For complicated and mostly non-technical reasons the device needs to assign so-called DLNA media profiles to images and media files. To start this, the device needs to go into idle mode once, so just let it rest for a while and all media created on the device should be available after that. This is a one-shot thing after the update, any files added afterwards will be fine.
Does any of my readers own or have access to a Samsung UE32B7070WW television and would be willing to help to debug a kind of weird browsing issue we’re seeing with this TV? Thanks.
gmmproc is a script used by most of C++ bindings of GNOME stack (called also mm-modules). It is responsible for generating actual C++ headers and sources from templates. That is so, because wrappers for most C API are straightforward, so writing them manually would be just a tedious job. Instead of that we just provide C API information, specify what names should C++ wrappers have and how to get a C instance from C++ one and vice versa and all happens automagically. Even documentation from C sources is taken and translated to use C++ names.
1 or 2 years or so ago.
Some time ago I was thinking about refactoring gmmproc. I was not the only one, because there were several notions that a rewrite could be welcome. I even made a topic on gtkmm-list about it and created a page at live.gnome.org. Main points would be using GIR as a source of API information and documentation, and getting rid of m4 as it makes it hard to add new features. I had some grand plans like creating two backends - one for defs (old API information) and GIR (new API information), creating conversion files on-the-fly, some configuration file a'la Doxygen, blah blah blah. Eventually I started some coding in Python, drawed some diagrams in my sketchbook, switched to C++ and then Perl and suddenly development slowed to molasses, because I already got bored. Apparently writing API structures is really uninteresting. Especially when it goes really slow and no end of it is in sight.
Now and ongoing.
I got back to it recently with a firm decision that I will finish it. I got over API structures by generating them basing on GIR definition I had to deduce from some python code in gobject-introspection (yeah, I wrote my own definition, because there seems to be none of such thing upstream - documentation is pitifully out of date). Also, most of the parser is also generated, but most important things are hand-written. Then I switched to refactoring a WrapParser and Output, which are 10 years old Perl code, added some needed infrastructure replacing m4, converted _CLASS_GOBJECT from m4/defs to Perl/GIR, added a scanner finding C <-> C++ type equivalents. My first aim is to have any compilable code being generated. For that still much work left to be done - mostly understanding and translating rest of m4 code to Perl (booooring!) and writing C <-> C++ conversion code (the one saying how to get `GtkWidget*' from `const Gtk::Widget&'; slightly less boring, but still).
Future plans are... no no no, no future plans for now. I did that before and got baffled by amount of work that needs to be done. Slowly all needed features will be introduced.
All of the code sits in gmmproc-refactor branch of glibmm. Additions here are mostly a bunch of kilo-line commits happenning once for two-three weeks, because I work on it offline at home in my free time. In the end all of it is going to be probably squashed into single commit before merging it to master.
I am usually pushing changes to repository when my single patch grows to at least 500kb. Now it has only 200 kb, so you have to wait. :)
If you try to test GStreamer 0.11 there’s this nice gst-uninstalled script; somehow that didn’t work for me as soon as I tried to use more non-gst interdependent libraries so I opted to use jhbuild. Luckily that’s quite easy with the stock gnome jhbuild moduleset.
To do that, I created a new .jhbuildrc-gst-0.11 with the following modifications. skip and modules can of course be adjusted to own needs.
moduleset = 'gnome-world-3.4' modules = [ 'vala', 'libgee', 'gstreamer', 'gst-plugins-good', 'gst-plugins-bad', 'gst-plugins-ugly', 'gst-ffmpeg', 'gssdp', 'gupnp', 'gupnp-av' ] skip = ['gtk+', 'atk', 'gcr', 'gtk+-2', 'rarian', 'NetworkManager', 'gnutls', 'polkit', 'p11-kit', 'gnutls', 'cantarell-fonts', 'gtk-engines', 'librsvg', 'gnome-themes-standard', 'libgnome-keyring', 'pango', 'expat', 'libgpg-error', 'libgcrypt', 'glib-networking'] os.environ['JHBUILDPS1'] = '[gst-0.11] ' branches = { 'gstreamer' : '0.11', 'gst-plugins-base' : '0.11', 'gst-plugins-good' : '0.11', 'gst-plugins-bad' : '0.11', 'gst-plugins-ugly' : '0.11', 'gst-ffmpeg' : '0.11' }
FOSDEM in 2012 was an exciting (and naturally, exhaustive) conference again. It's great to have so many relevant people who are all active in the free software world together in one place. It's also a great opportunity to discuss radical new ideas, ideally while experimenting with Belgium beer. Which is what we usually did when we weren't at the conference site.
It was nice to see Jarno and Esko at the conference, too. We even stayed in the same hotel. I hope they enjoyed the Ethiopian lunch as much as I did. And perhaps they're not too angry any more that we lead them to drink Absinthe ;-)
Jon and I gave two talks. Jon's talk (slides) was about Maliit as a project, explaining what Maliit is (and what it is not), combined with a short history lesson about the project. I tried to outline the difficulties of mobile text input in general (slides), picking some use-cases that are known from the desktop world and showing why simply copying the use-cases and their known interaction models does not work very well. I honestly liked Jon's talk more though.
Neither of us two actually managed to visit other talks, even though we wanted to. We had to ask Jarno, Esko and others about what great talks we missed. Apparently there were quite a few :-(
Our Maliit T-Shirts were well received, though we usually only handed them out when someone listened to our Maliit ramblings long enough.
We were asked about accessibility several times, which is currently not within the scope of Maliit but perhaps something to think about in the future.
We also got to talk with the people working on (text) input in Redhat and Intel, mostly in the context of Wayland. There are some interesting opportunities to get things (more) right this time around.
Thanks to our employer, Openismus, for sending us there!
Here are my slides to the short talk I did today about Rygel here at FOSDEM.
A few Openismus people will be at FOSDEM In Brussels this weekend. FOSDEM is always a great conference, but I can’t be there myself as my travel is generally limited by the need to take care of my kids.
Michael Hasselmann and Jon Nordby are both giving talks about the Maliit input method framework, as seen on the N9. We are eager to find customers who need our help to integrate and improve this only real choice for an open-source on-screen keyboard. So we hope that some people of influence take the opportunity to get to know the project and its excellent developers.
Jens Georg is also giving a talk about Rygel, used in the N9 to support UPnP and DLNA. For German speakers, there are already video and slides online of a recent talk that Jens did about Rygel in Berlin for Deutsche Telekom’s Developer Garden. I was amused to discover that DLNA had specified themselves into a situation where a minimum certified server and a minimum certified receiver were only able to share a small resolution JPEG format. Apparently it’s getting better, and Rygel can deal with it all.
Online Glom’s standard UI strings are now translated too, instead of just the strings that are in the .glom files. I added some initial translation files (mentioned here too) but I need people to translate them, please. Feel free to just email the file to me. I am tempted to add them to the desktop UI’s translations so I can copy them across.
I also changed it from using a lang= token in the URL to using GWT’s regular locale= query value, re-simplifying much of my previous Online Glom code to support translations.
Now that I see how each new translation adds another set of gwt-java-to-javascript permutations to the already-slow build, so it now builds 41 permutations, I might switch later from the Constants to the Messages technique for GWT translation, because I don’t think that string lookup will be a big performance problem.
In General
I know I have been quite silent about Rygel in general lately because I was quite busy with my day job. Since Zeeshan left Nokia after the MeeGo turmoil I took over his task of bringing Rygel in good shape to form the basis for Harmattan’s DLNA functionality.
These efforts, started long ago by Zeeshan, are finally coming to a close and entering the wild. With the release of PR1.2 beta for the N950, the alert reader might have spotted the release note entry “Media sharing with DLNA compatible devices”. You can probably guess what that’s powered by
One of the goals that we’d set ourselves has already been reached. The device is UPnP certified. The DLNA compatibility is in really good shape as well.
That is one of the reasons why the upstream Rygel development looks kind of stalled. The other one is that we’ve been focusing on ironing out the rough edges with emphasis on stability. Naturally, all of the patches that resulted here have been upstreamed, either to Rygel, GUPnP or libsoup.
On the device
So what’s on the device? A more or less pristine upstream snapshot taken several commits after 0.11.3 with later patches cherry-picked and some minor adjustments to adapt ourselves to the environment, like different device details and icons.
What can it do?
It implements a M-DMS, a mobile media server, enabling you to share the media content of your phone in your home network.
In addition to the rather useless mandatory media formats defined by DLNA we have decided to include a LPCM transcoder and the necessary profiles to share all the videos and images you’re going to take or already have taken on the device.
The server runs in a strict sharing mode where only media files that conform to one of the supported DLNA profiles are shared. This is configurable and we plan to release a “tweaking app” later to help the average end user to fine-tune and undo some of the limitations that had to be done due to the DLNA guidelines.
So, to all that already can, enjoy Rygel on your mobile phone.
Introduction
The development for Maliit, a cross-platform text input method framework for mobile devices, until 0.8 was mainly based on requirements for MeeGo Harmattan, the operating system on the Nokia N9. Harmattan applications are fullscreen. Animation of orientation changes is, together with other animations, done by the application. This is in contrast to Maemo Fremantle on the Nokia N900, were such animations were done by the X window manager.
When the virtual keyboard is up, the application remains fully interactive. Instead of using a proxy text entry, the text input goes directly to the application’s focused text entry. Showing the virtual keyboard should not change the layout, nor can it affect the application’s stability. The virtual keyboard runs in a separate process (maliit-server). But it requires animations showing, hiding and switching between different language layouts. In addition it should be possible to display overlays for word candidates or extended keys.
To satisfy these requirements the virtual keyboard window is shown in fullscreen mode. The visible parts of the virtual keyboard cover the bottom area of the application and screen, whereas the remaining area of the toplevel window is seemingly translucent. This keeps most of the application visible, including the focused text entry, which will render any text input immediately. It is also possible to pan the application’s page contents and to switch focus to another text entry, or remove focus altogether.
Shaped input region
To pass input events through to the application we use the shape extension of the X server and XFixesSetWindowShapeRegion to set the input shape of the MPassThruWindow to the region which the virtual keyboard and overlays really occupy. The X server will deliver events inside this region to the input method, and the rest to the application window.
void MPassThruWindow::updateInputRegion()
{
XRectangle * const xrects = convertQRectanglesToXRectangles(region.rects());
const XserverRegion shapeRegion =
XFixesCreateRegion(display, rects, region.rects().size());
XFixesSetWindowShapeRegion(display, winid, ShapeInput, 0, 0, shapeRegion); XFixesDestroyRegion(display, shapeRegion);
delete[] xrects;
}
Compositing Window Manager
When the window manager supports compositing, it is possible to use 32 bit translucent RGBA windows for the overlay. Mcompositor, Harmattan’s window manager, supports this feature. That is why we turned the background of the top level virtual keyboard window translucent. In Qt this can be done like:
MPassThruWindow::MPassthruWindow()
{
setAttribute(Qt::WA_TranslucentBackground);
}
Since compositing window managers are widely available for Linux desktops and the performance is acceptable it has been the default for Maliit 0.8.
Direct rendering
When the active application window is fullscreen and the application features a non-translucent background (which is the case on Harmattan), then the redirection of the active window into an off-screen window and additional compositing is unnecessary. Under circumstances, this redirection cuts the frame rate in half, which was unacceptable for animations and scrolling. For that mcompositor supports direct rendering of the active window into the frame buffer.
Since in this mode the keyboard window is transparent mcompositor cannot use the direct rendering optimization. Additional the context switches between the three processes, application, keyboard and compositor results in increased latency for text input, which affects the user experience. To reduce latency we wanted to further optimize performance for Harmattan and the N9 by using direct rendering with a 16 bit window for the keyboard.
Compositing using shaped output region
Our first approach used the same technique for the in- also for the output, with the help of XFixesSetWindowShapeRegion:
void MPassThruWindow::updateInputRegion()
{
...
XFixesSetWindowShapeRegion(display, winid, ShapeBounding, 0, 0, shapeRegion);
...
}
This solution does not require a compositing window manager but made it difficult to use shadows and overlays. It also was not performing as well as expected, since there is no support for direct rendering of shaped window. A better solution had to be found.
Compositing in Maliit
We were able to try another approach for using direct rendering. A 16bit RGB window together with the composite and damage X extensions is used to compose the content of the application window into the background of the virtual keyboard window. Instead of using the window manager for the compositing, Maliit handles the compositing itself.
The application window is represented through MImRemoteWindow in Maliit. XCompositeNameWindowPixmap is used to get a pixmap of the application’s window content:
void MImRemoteWindow::setupPixmap()
{
xpixmap = XCompositeNameWindowPixmap(display, winId);
pixmap = QPixmap::fromX11Pixmap(xpixmap, QPixmap::ExplicitlyShared);
}
This pixmap is blitted into the background of a QGraphicsView:
void GraphicsView::drawBackground(QPainter *painter, const QRectF &rect)
{
painter->drawPixmap(rect.toRect(), remoteWindow->pixmap(), rect.toRect());
}
To get notified about updates in the application window the damage extension is used:
void MImRemoteWindow::setupDamage()
{
damage = XDamageCreate(display, winId, XDamageReportNonEmpty);
}
On damage events there is a signal emitted, which is used to trigger a repaint.
void MImRemoteWindow::handleDamageEvent(XDamageNotifyEvent *e)
{
XserverRegion parts = XFixesCreateRegion(display, 0, 0);
XDamageSubtract(display, e->damage, None, parts);
QRegion region(convertXRegionToQRegion(parts));
XFixesDestroyRegion(display, parts);
Q_EMIT contentUpdated(region);
}
When handing over compositing from the the window manager to the input method process brief flicker can occur. To suppress it, mcompositor had to be patched to only map the virtual keyboard window after the application window has gotten redirected for compositing in Maliit. Additional QWidget attributes need to be set for all QWidgets in the virtual keyboard:
MPassThruWindow::MPassthruWindow()
{
setAttribute(Qt::WA_OpaquePaintEvent);
setAttribute(Qt::WA_NoSystemBackground);
}
In addition to improving the performance this approach also allowed to synchronize the rotation animation of the application and keyboard.
This mode is used on Harmattan and the Nokia N9 and can be activated by starting maliit-server with the -use-self-composition flag.
Plugins
Since plugins up until Maliit 0.8 are using fullscreen sized children widgets of the MPassThruWindow, their sizing and positioning depends on the toplevel window being a fullscreen window.
For compositing in Maliit to work, those widgets have to blit the application window content into their background. A QGraphicsView for example can use MAbstractInputMethodHost::background to paint the application window content as its background in QGraphicsView::drawBackground.
Conclusion
The fullscreen keyboard window approach was the proper choice for the Nokia N9 device. But on other devices, where orientation change animations are done by the compositor, or on a desktop system without a compositing window manager a non-fullscreen keyboard window could be a better choice. Unfortunately input method plugins based on Maliit 0.8 releases are tied to the fullscreen keyboard window concept and even need to take care for implementation details like the compositing in Maliit. The Maliit 0.9 series, which provide the basis for a first stable 1.0 release, should be used to find a better solution for plugins which allows different window modes and makes it easier for plugin developers by not burden them with any implementation details.
Building gwt-glom
At least on Ubuntu, it’s now easy to build and test gwt-glom. You can just do:
$ sudo apt-add-repository ppa:openismus-team/openismus-glom-unstable $ sudo apt-get install default-jdk maven2 libjava-libglom-java glom-utils $ git clone git://gitorious.org/online-glom/gwt-glom.git $ cd gwt-glom $ mvn gwt:run
This opens the GWT Development Mode GUI, which serves gwt-glom via jetty and lets you see it in your browser.
Chrome is the most likely to have the gwt plugin that you need for development mode, though it’s available for some versions of Firefox.
How we made it this easy
GWT projects, like other Java projects, typically use maven (mvn) for their build system. maven is nothing like autotools.
Maven usually downloads dependencies automatically, either from the central maven repository, from some (maybe private) other maven repository that you specify. This sounds unstable, but you specify exact version numbers, so you can be sure that your project will continue to build. So maven doesn’t have the separation of building and packaging that I’m used to in the C/C++/autotools world. It feels odd to me, but I’m going with the flow.
However, java-libglom uses JNI to provide a Java API around a C++ (libglom) API, so it uses both Java (architecture-independent) and C++ (compiled and linked for particular architectures).
java-libglom installs a native shared libary. We packaged that for Ubuntu in our Glom PPA (stable and unstable) as libjava-libglom-java so you can install it easily.
java-libglom also creates .pom and .jar files (for the API, the sources, and the javadoc). These are in the central maven repository so maven can just download the .jar.
That libjava-libglom-java Ubuntu package also installs the .pom and .jar files that maven needs, but those are only useful for mvn-debian, which is apparently only useful for building other Debian/Ubuntu packages. There is no apparently no way to using mvn-debian’s local repository while also using the central maven repository for other stuff.
Java with autotools
By the way, java-libglom uses autotools, although the autotools Java support is barely useful and limiting, so we have custom rules for most stuff. However, autotools does let us generate the Java and C++ files from swig, and build the native shared library. That seemed harder to do with maven, though maven would have made it easier to deal with the generated Java code.
I do like how maven just defaults to using your .java files, and test ,java files properly if you put them in the correct places. For instance, see the maven quickstart project.
This week I changed libglom’s TranslatableItem API to allow Online Glom to use the recent translations of the Glom example files. This requires the latest unstable version of libglom-1.22 and java-libglom.
There is now a language drop-down list at the top-right, and that is shown in the URL as, for instance, &lang=de (I might change that to locale instead of lang). Choosing a different language will change the table titles, field titles, group titles, etc, to the chosen language.
I have deployed that to the Online Glom test server. For instance:
I have not yet done the same for the translatable strings that are in gwt-glom’s Java source code, such as “Search”, and the “Open” and “Details” buttons. I’m not much looking forward to the awkward way that it should apparently be done. gettext’s _() macro is much cleaner.
Meyah and Liam had their birthdays a few days ago – Meyah on the 25th of December and Liam on the 29th.
Meyah is turning out to be just as friendly, energetic and curious as Liam. She’ll be walking soon. This is her second week in the creche, which will be good for her, but feels strange for us.
Liam wants to learn about everything and surprises me every few weeks with his sudden advances. Last week he learned how to play chess though a month before he would not have had the patience.
Raising two kids isn’t easy at times, but it’s the whole point of my life now and nothing has ever made me so happy.
I just implemented my first feature in Online Glom after taking over from Ben Konrath. Luckily I could cargo-cult his work, with some help from Eclipse’s code navigation and refactoring. I added a text box for an easy full text search of the current table, to filter the rows shown. For instance, you can filter the list of packages here.
I’m proud of myself, but I can’t help feeling that it needed far too many code changes, in far too many interconnected classes, just to add a text box in the browser and then use the resulting text to slightly change a method call on the server. I took the time to write a detailed ChangeLog/commit-message just to be sure that I understood what was happening.
This is apparently how things are in the land of Java. In its defence, there are reasons for the abstractions and separations. For instance, OnlineGlom code does the GWT thing of allowing for different View implementations for different clients, such as mobile or desktop, but it only has one type of Views for now. It also uses a Model/View/Presenter architecture, via its Activities, which makes it possible to test more code logic without getting the UI involved. And there’s the Places idea, which maps history tokens (parts of URLs) to Activities and vice-versa.
I wish there were some way to have the useful architecture without the repetitive code that gets in the way of the interesting stuff.
Maliit has an architecture where input methods are implemented as plug-ins. This enables a multitude of different input methods to exist and be used in the same way by applications. Maliit comes with a set of reference plug-ins, but there are also third party plug-ins. This video gives a quick introduction to some of them:
We finally published a video about Maliit - an input method framework including a virtual keyboard - and 3rd party plugins. Kudos goes to Jon for making time for that.
This video highlights one of Maliit's key features: pluggable input methods which come with their very own user interfaces. The Chinese input methods show how Maliit offers support for composed characters. The video is proof that 3rd party development for Maliit (open-source and proprietary) is not only possible but also happening.
maliit.org states that "it should be easy to customize existing input methods or develop powerful new input methods, whether for profit, research or fun", we actually mean it.
The harder question is of course how to motivate others to actually get started on input method development with Maliit. For that, we have a multipronged strategy:
-
Provide sufficiently polished reference plugins that can show off Maliit capabilities but also serve as inspiration for new plugins (hence the BSD license for reference plugins). Our reference plugins are currently using Qt/C++ (Maliit Keyboard) and QML (Nemo Keyboard). We also have PySide support, but no one contributed a reference plugin yet. This gives choice to interested input method developers, and we think that's important. The reference plugins serve another role when it comes to designing new API: They become our testbed, allowing us to verify our API proposals.
-
Ship Maliit with a bunch of example plugins and example applications. None of them try to be complete. They are all self-contained though and usually show one feature at a time. This can be tedious to maintain, but we believe that examples need to stay small and focused, otherwise developers won't look at them.
-
Documentation that is easy to consume. Our documentation is not as concise and clear as we'd like it to be, but it's slowly improving. We also experiment with videos that can serve as an introduction to more in-depth (text) documentation.
-
Packages for most common Linux distributions. This one seems obvious, but sadly, it's quite a lot of work for us to keep up with it (and we already use automated services such as Launchpad and OpenSuse Build Service). In the hope to attract dedicated packagers we wrote down some packaging guidelines
-
An architecture that had 3rd party plugins and multiple toolkit support in mind from the start. The plugin developer facing API needs to be easy to use and clearly documented. This will be the focus of the upcoming 0.9x series.
We will demo Maliit @ FOSDEM 2012, hope to see you there!
Glom‘s files can contain translations for the various table names, fields, relationships, choices, layout groups, reports, etc. This lets multiple people use the same database UI in different languages. Glom doesn’t require programming, so the .glom files don’t use gettext. But Glom can export the translations to .po files so translators can use their familiar tools. This week I added some command line utilities to do that more easily, plus some make rules to use them on the Glom examples.
I can now type “make examples_export_po” to export .po files and “make examples_import_po” to read the improved translations back into the Glom example files.
I put the .po files in Glom’s git repository, hoping that people will translate them, and maybe add more .po files. I wonder if these could even show up on Glom’s l10n.gnome.org page. Update: They do show up there now, thanks to Claude Paroz, and we already have some translations.
Ben Konrath recently finished up a first real milestone in Online Glom development, and I have deployed it, with the example Glom files, on an Amazon EC2 instance. Online Glom is still a read-only UI, so you can’t edit data in the database, but I think it’s already useful for some situations. Well, I do want to add the quick search feature soon to really finish off the read-only functionality. Report-generation would be good too.
The Film Production Manager example is a fairly good example of the complex systems that Glom can support, without SQL and without programming.
Here’s a screenshot of the same thing in the desktop UI.
I have also deployed my old Debian Repository Analyzer, full of real data, so you can get a feel for navigating around the related records. I spent lots of time updating that for the latest python-apt API and libgda (with python) APIs, and it’s now in a gitorious project. Many thanks to Michael Vogt for his help with python-apt.
Now that David King has packaged java-libglom (as libjava-libglom-java) for Ubuntu Oneiric in the Openismus PPA, it’s really easy to work with the gwt-glom code on that distro.
What’s Next
This proves that GWT was a sane choice, though development has not been as quick as I’d hoped . But I don’t think a generic framework can ever be developed as rapidly as most data-driven web sites that start as quick hacks. The difficulties have shown that I was right to focus on a restricted set of functionality at first. You can get a sense of how development has progressed by looking at the gwt-glom commit log, though there’s lots of work in java-libglom too.
I now plan to take the development further myself. That’s a nice way to get more deeply reacquainted with Java and web development. It’s easier to hack on the project at this stage, before it gets huge, rather than trying to do this from scratch. Ben Konrath has already made the large architectural decisions so that I don’t have to. I’m even enjoying Eclipse, which is a much more pleasant experience with Java than with C++. Well, using the Eclipse IDE is still like shopping in a flea market but with Java you will quickly find useful things.
I plan to do things roughly in this order:
- Add the Quick Find feature, for searching. Update: Done
- Add report generation.
- Add print layout printing.
- Maybe investigate how to make theming via CSS easier.
- Allow editing of data. This will be a big task.
At the same time, I will play with avoiding the need for java-libglom’s JNI binding to the libglom C++ library. I would need to reimplement Glom document parsing in Java, but that would be easy as it’s just XML. But I would also need some replacement for GdaSqlBuilder, to build SQL queries without manually concatenating and escaping text.
In Maliit, all changes have to be reviewed by two people in order to be merged to mainline. This helps us catch issues early and keep code quality high. Since the code is hosted on Gitorious, we use their merge requests feature for that purpose. Up until now we have periodically checked the website for changes (potentially going through each and every one of the repositories), and manually mentioned updates in the IRC channel. This is both tedious and inefficient, so I wrote a simple tool to help the issue: Gitorious Merge Request Monitor
It provides an IRC Bot which gives status updates on merge requests in an IRC channel:
16:01 < mrqbot-AfFa1> desertconsulting requested merge of ~desertconsulting/maliit/desertconsultings-maliit-framework with maliit-framework in http://gitorious.org/maliit/maliit-framework/merge_requests/126
16:01 < mrqbot-AfFa1> mikhas updated http://gitorious.org/maliit/maliit-framework/merge_requests/125 State changed from Go ahead and merge to Merged
One can also query the current status from it:
15:02 < jonnor> mrqbot-7ACeB: list
15:02 < mrqbot-7ACeB> maliit-framework/127: - New - Allow QML plugins to add custom import paths for QML files and QML modules
15:02 < mrqbot-7ACeB> maliit-framework/126: - Need info - configurable importPath for qml
15:02 < mrqbot-7ACeB> maliit-plugins/26: - New - Add PluginClose from main view and add key repetition support
15:02 < mrqbot-7ACeB> maliit-plugins/25: - New - Clear active keys and magnifier on keyboard change
15:02 < mrqbot-7ACeB> maliit-plugins/24: - New - Remove QtGui dependency from libmaliit-keyboard
15:02 < mrqbot-7ACeB> maliit-plugins/23: - New - Get rid of Qt keywords
15:02 < mrqbot-7ACeB> maliit-plugins/22: - New - Add phone number and number layout getters.
Status changes are retrieved by periodically checking the Gitorious project activity feed (Atom)*, and the status itself is scraped from the website. There is no other API right now, unfortunately. Implemented in Python with Twisted, feedparser and BeautifulSoup doing all of the heavy lifting.
Get it from PyPi, using easy_install or pip:
pip install gitorious-mrq-monitor
gitorious-mrq-monitor --help # For usage information
For now this solves the immediate need for the development work-flow we have in the Maliit project. Several ideas for extending the tool are mentioned in the TODO. Contributions welcomed!
After having set up the typical things open source projects needs like a website/wiki, mailing-list and bug-tracker, Maliit now also has something not so common: a build-bot.
As Maliit consists of several components that can be built in several different ways (and for several different platforms), we wanted to automate the build and tests of the different variations to ensure that we do not break any of them. This is especially important for variations which are not easy to test for the individual developers, like for instance Maliit on Qt 5.
The software chosen to help with this task was Buildbot. Getting an initial instance it up and running was very quick and pain-free, especially thanks to packages being easily available and the excellent documentation. The current setup now builds, tests and installs the two major components we have: Maliit Framework and Maliit (Reference) Plugins, in the most important build/config variations we have. A total of 12 individual build jobs, plus 2 meta-builds. The configuration for the instance can be found in the maliit-buildbot-configuration repository.
For security reasons the build-bot is not directly exposed to the Internet. Instead a script runs every 5 minutes to generate a static HTML website and publish on the public web-server: Maliit build-bot
This gives us a minimal continuous integration system for Maliit, which for now will hopefully helps us avoid breakage. In the future, the usage of the build-bot might extend to include:
- Automating the release process
- Testing of merge-requests/patches before merging to master
- Automated integration/system testing, complementing the unit-tests
- Triggering external builders for packaging. OpenSUSE OBS, Maemo 5 Garage, etc.
- Automating certain aspects of bug-lifetime. Resolving when fix is committed, closing on release if pre-verified, etc
Inspired by someone's lazyweb call I felt like doing something entirely unrelated to my regular work.
libstarred provides a GTK+ cell renderer and a widget for showing and editing five-star ratings.
Feel free to use it. Merge requests welcome. Ideally someone finds time to polish it for inclusion into GTK+ itself.
Btw, hacked using QtCreator's Autotools Plugin.
The Maliit developers and the Plasma Active developers, with some Mer developers too, discussed yesterday how they can work together. Reading the irc log, it seems to have been productive, with great input from all groups, and with some first development steps planned.
As always, I’m proud of our Maliit developers at Openismus. We believe that excellent developers must be communicators, or their work is for nothing. That log shows why.
Qt 5 has a complete new interface for input methods. Instead of the old QInputContext (which is just a wrapper around the new system now) there is now QInputPanel and QPlatformInputContext (no documentation yet, see source), for the reasoning see QTBUG-20088 – Create proper input method abstraction and expose it through a public API in QTGui.
Luckily there is already a simple platform input context for the Maliit input method framework in the Qt code base available. There are some smaller bugs open, but they should be easy to fix. So it should be already possible to use Maliit with Qt 5 applications.
Additionally we would of course like to compile Maliit itself against Qt 5 too. Based on the previous work eliminating the X requirement in Maliit it was a quite easy task to compile it with Qt 5 and required just fixing some smaller bugs and updating some build system files.
After that I tried to run Maliit with the XCB platform. This showed an ugly bug, the virtual keyboard stole the focus from the application. On Qt 4 we used the WA_X11DoNotAcceptFocus Qt::WidgetAttribute which does not work for the XCB (and Xlib) platforms in Qt 5. I filed a bug about this issue and created a patch (which is sadly only visible when one has a gerrit account registered). With that patch applied to Qt 5 Maliit was basically working.
We kicked off the new 0.81 release series together with a nice announcement: We have our own bugtracker now!
This means that Maliit has a near complete project infrastructure, all available under *.maliit.org, and all that thanks to Karsten, the always professional and very experienced hostmaster here at Openismus.
There is one more thing that we need (as demonstrated by me when I made my first broken release), and that's a simple build bot setup for continuous integration. Right now, we still rely on Nokia's infrastructure. I am confident that buildbot will fit all of our requirements, as long as it is trivial to maintain.
I am also happy that we improved our documentation significantly, thanks to Dave. He translated the important documentation bits into proper English and made it more accessible, demonstrating his doxygen skills. As a bonus, he also updated the project's README files, something we had neglected for a long time.
Future development
Regarding the Maliit development, I think we have simplified things a lot. D-Bus activation for the Maliit server (which finally means one server instance per user session) and the new support for plain QML plugins makes it almost trivial to get started with Maliit. We also let go of the critically acclaimed MeeGo Keyboard in Maliit upstream, which made me a bit sad of course.
Still, it probably was the right decision: MeeGo Keyboard is heavily fine-tuned for Nokia's N9 and it has some dependencies that are hard to satisfy outside of Harmattan. Over time, with ever changing requirements, the code has naturally evolved into a rather complex design. The result, however, is a very polished product, and ultimately, that's the only thing that matters (even though many opensource developers will disagree, strangely enough). Everyone in the team is proud of what we have achieved.
At the same time, I can understand how new contributors will be put off by all the complexity. So Maliit upstream will instead focus on the very basic but almost trivial to build Maliit Keyboard. For new contributors, that's a good thing. For us, it means the possibility to fix shortcomings in the plugin API. This is important, as one of our main goals has always been to enable others to write great input method plugins for Maliit, which will then run on any platform that Maliit supports. The Swype VKB plugin and the Japanese VKB plugin for example both demonstrate that we are on a good way, but I think we can do better.
Maliit itself still needs a good reference plugin, of course, even if only as a showcase (though I want it to be more). All this doesn't mean that MeeGo Keyboard goes away; its development will continue in the MeeGo Touch repositories, just as before (effectively degraded as just another Maliit plugin). But what we can take over, hopefully, is our experience when it comes to creating one of the best virtual keyboards currently available.
The Openismus employees who worked on the N9′s Harmattan project received their free Nokia N9 phones from the company yesterday. It was expensive but its the right thing to do.
I released version 3.2.0 of the Programming with gtkmm book, with many corrections and updates from Kjell Ahlstedt and a small chapter about keyboard events from Pedro Ferreira.
As usual, it is available on the Kindle too.
It has taken over a year of hard work but Glom 1.20 is finally ready. 
This is the most stable and most usable version of Glom yet, with a few new features, now using gtkmm 3. Here are some updated screenshots. The major changes:
- Simplified main window.
- Glom can now store and display PDFs. It can store any file format, though it can only display images and PDFs.
- Print Layout: Major overhaul with improved UI and new functionality.
- Related Records: Allow the developer to specify how many rows to show.
- Choice drop-downs can show more than 2 fields.
- Choice drop-down fields are aligned.
- Choice drop-downs can show related fields.
- List columns have sensible widths.
Around 20 bugs from bugzilla were fixed, plus several more.There are over 30 tests that prevent regressions in mostly non-UI code. I still wish I could get some kind of automated UI testing working.
We have packaged Glom 1.20 (and several dependencies) for Ubuntu 11.10 (Oneiric) in the Openismus PPA. We might do something similar for Fedora.
Unfortunately, it will probably take a year for Glom 1.20 to officially get into distros such as Ubuntu (bug) and Fedora (bug)officially, and then they won’t deliver bug fix updates. This is partly due to lack of the volunteer packagers’ time and partly due to unfriendly distro policies towards applications. My only hope now is something like Glick.


































