Random deep thought of the day

“What strikes me is the fact that in our society, art has become something which is related only to objects and not to individuals, or to life. That art is something which is specialized or which is done by experts who are artists. But couldn’t everyone’s life become a work of art? Why should the lamp or the house be an art object, but not our life?” – Michel Foucault

Learning a foreign language

One of the advantages of not being a native speaker of this wonderful mess existing under the umbrella term of ‘English language’ is that you will truly appreciate things like the following:

Waterfall is the opposite of firefly.

Seems legit to me.

The most interesting variant of this pluricentric language is definitely Engrish. And it is somewhat a secret language, since you cannot find courses or books for it. It has no semantic or syntactical rules, but relies entirely on intuition and creativity. This miracle language has recently gained popularity in eastern Asia.

engrish-lol28Engrish_44fa87_299912

189597d9d8968e05fe727368ee92df82

 

Have chinchillas been giving you nightmares lately? If you do not associate chinchillas with cuddly rodents, but orthographic nightmares, chances are high that you are a student of the Russian language. This is the word шиншилла in russian cursive script:

1426002913_1004627246

 

If your hovercraft is still not full of eels yet, try German ( not a foreign language to me, so I might be somewhat biased ) :

long_german_words

Oh, come on, it’s just an elementary word. Read some fiscal laws for some mindblowing experience and you will end up learning Italian which is basically a collection of loosely coupled vowels.

Have fun learning languages!

 

Inkjet printer woes

WhatsApp Image 2017-06-13 at 20.17.21

What a wonderful contraption is an inkjet printer! Countless different models of so many manufacturers are out there, only to be constantly superseded by new models with new innovations, such as new number or letter suffixes for the name. A new suffix for the printer model can decide between flawless driver integration and driver selection hell, when you try to match the printer’s name to the available driver out of 10^6 options.

If you let these things autoinstall the software they come packaged with, be prepared for a big ball of mud that will drain your system’s resources after installing all the things they throw at you, none of which are actually required for printing.

And this is only scratching the surface. Continue reading at your own risk, but think well before, if you can stomach it.

Inkjet printers depend on a mythological substance that would have been probably praised by medieval alchemists for its elusive qualities. Printer ink. On a metaphysical level, curses are the second, intangible ingredient for operating a printer, but at least they don’t strain your budget ( unless the penal code of your country implements fines for cursing ), and therefore will not be covered here. With printer ink, you are not that lucky.

Ink cartridges are sometimes more expensive than the printer. And it leaves one wondering where all the CMYK and black ink vanishes to. Internet lore even tells us about printers accumulating black goo somewhere on the inside just to trick the customer into buying new cartridges. Since many printers clean their nozzles by flooding them with ink, the story cannot be dismissed entirely as a legend. Even the alien trilogy has picked up the subject of black goo, where fittingly everybody who touches the black goo is turned into a mutant. A subtle warning against disassembling your printer perhaps? Disclaimer: I have not witnessed any cases of mutation yet, only tears and curses over the wasted ink so far.

And nobody knows why printers can be huge and have really tiny cartridges. The HP Deskjet 4100 on the bottom of the printer stack in the picture is huge, its cartridges are tiny and its hunger for ink inexhaustible. Also these cartridges have the printing head attached to them, to make them more expensive and harder to refill or replace with imitation products.

Let us take a look at the lifespan of the average inkjet printer. Once they are in use, they are required to exercise their printing prowess every few months or dry up. If the ink dries up inside the printing head, all that will be left is a big hunk of garbage.

Happened to me with the second printer in the row, the Canon Pixma IP4200. I tried cleaning it with alcohol, but the only result was that my hands looked like Van Gogh’s after a psychotic painting seizure.

Regardless of what I do, black PGBK does not print even a dot. This problem occurs so often and forums on the net are filled with it, that many have used the word planned obsolescence to explain its frequent emergence.

What can you do with an old printer? Absolutely nothing. People will not even take it, if you offer it for free. If you are the flowery kind of person you can remove the printer’s innards and plant some flowers inside. Or if you are lucky enough to have ample storage space, you can cram your old printers in there and offer them to posterity some decades later as dreadful artefacts from the past that drove people crazy.

My advice on inkjet printers:

-try to avoid them

-if you can’t, get one with cartridges that come without electronic circuitry attached to them. They are cheaper to refill.

-buy an all-in-one thing that can also scan and copy. It will safe you some space.

 

 

 

Building a CalDAV interface – Request and Response example

A couple of months ago, I was tasked with building a CalDAV interface for calendar synchronization with an existing, but highly customized webserver with an existing calendar application from scratch. An impressive number of implementations already exist, most in the open source spectrum. But what I could not find was a step by step guide covering the whole communication from discovery to item delivery. Studying the sources is very insightful, though not very efficient. Reading the convoluted rfcs deprecating each other is even worse. So here is my attempt at a basic, language-agnostic guide.

CalDAV uses the standard http methods like GET and PUT, inherits some from DAV, like PROPFIND and defines also its own like REPORT. Let’s take a closer look at the main request types.

OPTIONS

This request is wonderfully simple. The server returns the supported subset of CalDAV functionality in the header and sends it to the client with http status 200 in a response with empty content. Note that it is not always the first request and may be sent after one or more PROPFINDs. An example for the headers that are returned would be this very basic set of features:

DAV “1,2,access-control,calendar-access”
Allow “OPTIONS,GET,DELETE,PROPFIND,PUT,REPORT”

PROPFIND

This request queries calendar and calendar item information, but not the items themselves. The client will send a sequence of PROPFIND requests on different targets to determine their properties. Properties are requested as tags in the xml body. The server should either return a value in the xml if the property is found or indicate its nonexistence by declaring its status 404. Lazy clients who do not want to enumerate properties separately will try something like:

<D:propfind xmlns:D=’DAV:’><D:allprop/></D:propfind>

The requested properties vary across clients. A typical example for calendar discovery would be this request-response ping-pong game from the Mac OS iCalendar application. PROPFIND and REPORT requests should return status code 207.

PROPFIND /caldav/marmoser

<A:propfind xmlns:A=”DAV:”>
<A:prop>
<B:calendar-home-set xmlns:B=”urn:ietf:params:xml:ns:caldav”/>
<B:calendar-user-address-set xmlns:B=”urn:ietf:params:xml:ns:caldav”/>
<A:current-user-principal/>
<A:displayname/>
<C:dropbox-home-URL xmlns:C=”http://calendarserver.org/ns/”/&gt;
<C:email-address-set xmlns:C=”http://calendarserver.org/ns/”/&gt;
<C:notification-URL xmlns:C=”http://calendarserver.org/ns/”/&gt;
<A:principal-collection-set/>
<A:principal-URL/>
<A:resource-id/>
<B:schedule-inbox-URL xmlns:B=”urn:ietf:params:xml:ns:caldav”/>
<B:schedule-outbox-URL xmlns:B=”urn:ietf:params:xml:ns:caldav”/>
<A:supported-report-set/>
</A:prop>
</A:propfind>

The response would look like below. Note the http status for the different attributes.

<d:multistatus xmlns:d=”DAV:” xmlns:cs=”http://calendarserver.org/ns/&#8221; xmlns:c=”urn:ietf:params:xml:ns:caldav” xmlns:ical=”http://apple.com/ns/ical/”&gt;
<d:response>
<d:href>/caldav/marmoser</d:href>
<d:propstat>
<d:prop>
<c:calendar-home-set>
<d:href>/caldav/marmoser/calendar
</c:calendar-home-set>

<d:principal-URL>
<d:href>/caldav/marmoser/principal
</d:principal-URL>
<d:supported-report-set>
<d:supported-report>
<d:report>
<c:calendar-multiget/>
</d:report>
</d:supported-report>
<d:supported-report>
<d:report>
<c:calendar-query/>
</d:report>
</d:supported-report>
</d:supported-report-set>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
<d:propstat>
<d:prop>
<c:calendar-user-address-set/>
<cs:dropbox-home-URL/>
<cs:email-address-set/>
<cs:notification-URL/>
<d:resource-id/>
<c:schedule-inbox-URL/>
<c:schedule-outbox-URL/>
</d:prop>
<d:status>HTTP/1.1 404 Not Found</d:status>
</d:propstat>
</d:response>
</d:multistatus>

We notice two different urls: a principal url and a calendar url. So what exactly is the principal url? Some clients require a principal url they can query information from. Some are satisfied with the root url and the calendar url.

Now that the calendar is known, the client will try to query it:

PROPFIND /caldav/marmoser/calendar

<A:propfind xmlns:A=”DAV:”>
<A:prop>
…..
<C:getctag xmlns:C=”http://calendarserver.org/ns/”/&gt;
…..
<A:resource-id/>
<A:resourcetype/>
…..
<A:supported-report-set/>
<A:sync-token/>
</A:prop>
</A:propfind>

Let’s look at the most important attributes in greater detail.

A ctag is an important value indicating if something in the calendar has changed, usually a hash.

supported-report-set will tell the client what the server supports. In our case, we indicate support for calendar-multiget and calendar-query methods for the REPORT method.

<d:supported-report-set>
<d:supported-report>
<d:report>
<c:calendar-multiget/>
</d:report>
</d:supported-report>
<d:supported-report>
<d:report>
<c:calendar-query/>
</d:report>
</d:supported-report>
</d:supported-report-set>

sync-token returns a value if your server supports  rfc6578  synchronization. The idea is similar to the ctag: the clients sends a sync-token, the server compares if and, if a change is detected, returns the delta between the client’s and the server’s token. This is not easy to implement, since you need a data model that supports calculating and storing the changes between two sync tokens.

resourcetype will return the type of resource found under this url. For a calendar it would be <d:collection/> with DAV namespace and <c:calendar/> with CalDAV namespace.

REPORT

Now as the client will try to get the hash values for the calendar contents, the etags. Notice the time range limitation and the filters restricting the results to VEVENT type ( no VTODOs oder other resources should be returned ).

REPORT /caldav/marmoser/calendar/

<B:calendar-query xmlns:B=”urn:ietf:params:xml:ns:caldav”>
<A:prop xmlns:A=”DAV:”>
<A:getetag/>
<A:getcontenttype/>
</A:prop>
<B:filter>
<B:comp-filter name=”VCALENDAR”>
<B:comp-filter name=”VEVENT”>
<B:time-range start=”20170412T010101Z” end=”20170503T010101Z”/>
</B:comp-filter>
</B:comp-filter>
</B:filter>
</B:calendar-query>

response:

<D:multistatus xmlns:D=”DAV:” xmlns:C=”urn:ietf:params:xml:ns:caldav” xmlns:CS=”http://calendarserver.org/ns”&gt;
<D:response>
<D:href>/caldav/marmoser/calendar/20161205T084507Z-153527473.ics
<D:propstat>
<D:prop>
<D:getetag>”0bdef6e4a53d616c314fa99ff6f24aa8″</D:getetag>
<D:getcontenttype>text/calendar;charset=utf-8;component=vevent</D:getcontenttype>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>

If the etag has changed, the client will request the ics data for this calendar item. In this example, only one item is requested, but it is possible to request more than one inside a multiget. Some clients are stupid and request only one item at the time, so beware of request storms coming from android apps. The url to the ics file in href should also work when requested with a GET, and some clients will go for this.

REPORT /caldav/marmoser/calendar/

<B:calendar-multiget xmlns:B=”urn:ietf:params:xml:ns:caldav”>
<A:prop xmlns:A=”DAV:”>
<A:getetag/>
<B:calendar-data/>
<C:updated-by xmlns:C=”http://calendarserver.org/ns/”/&gt;
<C:created-by xmlns:C=”http://calendarserver.org/ns/”/&gt;
</A:prop>
<A:href xmlns:A=”DAV:”>/caldav/marmoser/calendar/20161205T084507Z-153527473.ics
</B:calendar-multiget>

Finally some calendar item data the client will be able to display.

<D:multistatus xmlns:D=”DAV:” xmlns:C=”urn:ietf:params:xml:ns:caldav” xmlns:CS=”http://calendarserver.org/ns”&gt;
<D:response>
<D:href>/caldav/marmoser/calendar/20161205T084507Z-153527473.ics</D:href>
<D:propstat>
<D:prop>
<D:getetag>”88e7895d9805b5835091108631f0ffb1″</D:getetag>
<C:calendar-data>BEGIN:VCALENDAR
X-WR-TIMEZONE:Europe/Vienna
CALSCALE:GREGORIAN
VERSION:2.0
METHOD:PUBLISH
BEGIN:VEVENT
CREATED;VALUE=DATE-TIME:20161117T092336Z
LAST-MODIFIED;VALUE=DATE-TIME:20161117T092336Z
DTSTAMP;VALUE=DATE-TIME:20161117T092336Z
DTSTART;VALUE=DATE-TIME;TZID=Europe/Vienna:20161117T150000
DTEND;VALUE=DATE-TIME;TZID=Europe/Vienna:20161117T160000
UID:20161205T084507Z-153527473
DESCRIPTION:Too wonderful for words
SUMMARY:Something wonderful
RRULE:FREQ=WEEKLY;BYDAY=TH;INTERVAL=1;UNTIL=20201116T230000Z
END:VEVENT
END:VCALENDAR
</C:calendar-data>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
<D:propstat>
<D:prop>
<CS:updated-by/>
<CS:created-by/>
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
</D:propstat>
</D:response>
</D:multistatus>

Keep in mind that this is only a very basic example and does not cover the immense range of CalDAV’s possibilities. Every client ( Mac OS X, iOS, android sync apps, evolution, thunderbird etc ) will send different requests and behave differently.

Trying the Solarized Colorscheme

Usually, I prefer functionality over aesthetic appeal. Sometimes those two terms cannot be fully separated or can be reconciled in a unity of both. An example for this is the colorscheme applied to a user interface.

I decided to give the Solarized Colorscheme a try, it is still quite a hype and supposed to be immensely popular.

Solarized was created by a man with the passion of an artist and the precision of a scientist who put unbelievable energies into finding the best colors for a programmer’s text editor. The result is remarkable and can be found here:

http://ethanschoonover.com/solarized

( I wonder where he got the name from. Was it the Stanislaw Lem novel, the Tarkovsky film, one of its remakes or the old fashioned unix brand? My guess is the latter. Ironically the default colorscheme of the unix variant was a visual nightmare. )

The result is a light colorscheme and a dark one, if your workplace gets enough daylight, you are supposed to choose the light one, if you shun daylight or love to work in the night, the dark scheme is for you. I almost work exclusively with the dark scheme, in daytime and nighttime.

Solarized themes exist for the console, gtk, some window managers and many editors.

Arch Linux provides about 30 packages in AUR for the search term. You can solarize about anything from mc, emacs, vi and mutt up window manager decorations, consoles and text editors.  My own hacky ( not strictly canonical in terms of text color choices ) variant for SciTE, which I created because I could not find any for this editor fitting my purpose can be found on my github: https://github.com/marmoser/config/blob/master/.SciTEUser.properties

It covers most of the languages I use, but still leaves many looking very ugly due to missing style definitions.

My conclusions: For long working hours, a colorscheme with dark background and brighter text causes less eyestrain. I’m not switching back to dark text on bright backgrounds anytime soon. If UI colorschemes are something like a religion, Solarized manages to appeal even to agnostics.

 

 

Movie review: Ghost in the Shell 2017

I can still remember watching the animated version in the 90s. Back then it was a mindblowing experience, especially for the early teenager I was back then. I never felt at home with anime, but this was different: bold ideas, bold questions and a paradoxical ending. And now I have the possibility to rewatch this in movie form – what could possibly go wrong?

Sadly, a lot. The movie tries to follow the original very closely, at least visually, initially also the original narrative, but at the cost of dumbing down the whole thing.

Examples ( hurray spoilers ):

-The villain of the original anime is some AI gone rogue. The ultimate sin of the movie was to replace him with some emo hippie.

-The real villain of the movie is a joke. Acting in the name of the government, yet always alone without any superiors. I guess they labeled him generic bad guy in the script.

Well, they have gotten the visuals right ( must be impossible to mess them up with such a budget ). But for the rest, expect a hollow shell without any ghost.

User experience: Android 6 ( with cm 13 ) on the Samsung GT-P3100 without google apps

Being the owner of a Samsung Galaxy Tab 2 7.0 I decided not only to upgrade the Android version to 6.0.1 with cm13, but also see how far I can get without google apps.

I have nothing against google, they provide valuable services and technology. However, I think their enthusiasm in collecting data has gone too far. I want a good search engine and a reliable mail service, I don’t want a service that logs every single thing I do through my google account, from the search terms I entered to the times I played chess on my tablet. Is all the data collection on your android phone really necessary? Yes, you can opt out of most of it, but still, who goes to the settings, navigates all convoluted and hidden menus just to disable google’s hunger for your data. I’m not paranoid, I just like to stay in control. So I decided to try my tablet without google apps.

Here it gets problematic. Using an unmodified android phone without a google account is flatly impossible and not accessible to the average user since it will not work without rooting your device and installing an alternative android distribution of your choice.

There is no other way of removing google services from your android device than rooting and overwriting the system with another OS. There should be plenty of material on the process around, so I won’t cover it here and focus on my user experience. An android device without google apps does not come without serious drawbacks.

Most importantly, android without google is android without the google play store, which is google’s idea of installing and updating new apps.

There is F-Droid with comparable functionality, but only with open source apps. For apps that are only available in the play store, there is only one way: downloading the apk and installing it manually, which is tedious and a threat to your device security: who would easily trust some 3rd party apk download? The easiest solution here is to retain the old apks you collected from your time on google play store and install them on the google-less device. Needless to say, this method is worthless if you want to install something entirely new.

Furthermore, many google play apps will not work without google play services and refuse to start or malfunction.

Creating a backup of your data is now your own responsibility. No auto-synching of contacts to google anymore. I export them now manually to a vcf file from time to time.

Here a small list of the apps that will cease to work and their replacements. I’m not a heavy user of those apps, enthusiasts might find the solutions frugal and not suitable for their productive use.

-Google calendar: Fortunately, there is a standard calendar application on android with the same functionality. Displaying the events from your google calendar requires a little work though: I used an ics importer from the f-droid repo and connected it to the private url of my google calendar. Problem solved. Beware that this is only a read access, but that is fine with me.

-Gmail app: Android standard email client does the job.

-Google maps: For some strange reason this apk installs and runs without complaining about missing google services.

-Whatsapp is no google app, but I include it since it has a high priority for many people. Whatsapp has its own autoupdate and runs without problems, only displays a warning once when installing. If you keep whatsapp’s history file on the device, it is easy to import your old messages, and you are prompted to do so.

Other apps of choice include mupdf for pdf reading, CoolReader for ebook reading and open cycle maps.

After more than three months without google apps I’m not switching back anytime soon. Certainly this is not everybody’s cup of tea, but maybe my little article has encouraged you to give it a try. Mobile devices are not intended to be very protective of the user’s privacy, so it’s up to you to take a small part of it back.

Android – Which are the best fonts for reading ebooks?

A multitude of apps for reading ebook formats exists for the android platform. As different as they might be, they have one thing in common: they use the default font bundled with Android. The font selected by default is Roboto or Droid, which is not really bad, but not optimized for reading thousands of pages either. So, in my opinion, what all those reader apps really lack is a good font.

A quick search on the net revealed that some fonts exist which were designed with the specific purpose of reading ebooks in mind. Amazon has developed the Bookerly font which is delivered with their kindle devices. The Literata font comes with Google Play Books. Both are a noticeable typographic improvement over the fonts available as default on Android in terms of readability. The question is how to get these fonts into your favorite reader app?They can be downloaded as true type fonts. In order to use them, it is enough to copy the file to the /system/fonts folder. Adding new fonts is possible on android without installing any third party apps if you have a rooted device. Why are there special apps for things that are as simple as copying font files to the font directory? Wonders never cease.I managed to find the fonts on this site:
http://www.newswirl.com/bookerly-font-download/
Direct links:
http://www.newswirl.com/wp-content/uploads/Bookerly.zip
http://www.newswirl.com/wp-content/uploads/Literata.zip
Which of the two fonts is actually better is very hard to say. Both are a great improvement over the standard Roboto font. I favor the Bookerly font, but ultimately this is a very subjective choice.

SWF archeology: how to retrieve the dimensions from a flash (swf) file

Embedding flash objects can be troublesome, if you don’t know the native resolution of the file you want to display.

Of course you can use the embed tag or the object tag and set its width and height to 100%, but you have to stop editing and view your page to find out how big the object actually is.

In a WYSIWYG html richtext editor a placeholder that has exactly the size of the swf object helps a great deal to get an impression how big the element will actually be when viewing it.

Let’s see how this can be accomplished:
swfs files store the width and height of the object in the file’s header.
All we need to do is read the file header and interpret our findings.

The first 3 bytes of a swf file indicate the file type.
FWS is the magic byte number for normal swf, CWS indicates a compressed file, where everything beyond byte 8 is zlib compressed. We can also find version info and file size in the header after byte 3, but this has nothing to do with the file’s dimensions.

Reading another 9 bytes starting with byte 9 (this is where the header ends) will give us a rect structure, which stores the file’s dimensions. Read it in high-to-low order.

If you don’t know what a rect structure is (I didn’t know either), fortunately things are well documented.

structure of rect
Nbits nBits = UB[5]
Bits in each rect value field
Xmin SB[nBits] X minimum position for rect
Xmax SB[nBits] X maximum position for rect
Ymin SB[nBits] Y minimum position for rect
Ymax SB[nBits] Y maximum position for rect
Xmax-Xmin will give us the dimensions for x. The length of the Xmax and Xmin field in bits is determined by nbits.

Still, the results appear off the scale. Nothing wrong here, x and y dimensions are stored in twips (some invention of ressourceful typesetters?). Just divide the results by 20 and you get the size in pixel.


Here is a simple example in tcl (if you are looking for examples in c, there’s an overabundance of them on the web):

set f [open $swffile r]
fconfigure $f -translation binary -encoding binary
set header [read $f 3]
set version [read $f 1]
#size is uint32
set size [read $f 4]
set data [read $f]
close $f

if {$header ni {FWS CWS}} {
  #file is not flash
  return
}

#if the file is compressed, uncompress it first
if {$header eq {CWS}} {
  #compressed file, uncompress with zlib
  #we could use something nicer here, like ns_zlib or the zlib package
  set fileID [open "/tmp/swfuncompressed_XXXXXX" w]
  fconfigure $fileID -translation binary -encoding binary
  puts $fileID $data
  close $fileID
  set data [eval exec "/usr/bin/openssl zlib -d -in $tmp_file"]
  file delete $tmp_file
}

#rect contains dimensions
set rect [string range $data 0 9]

#structure of rect
#Nbits nBits = UB[5]
#Bits in each rect value field
#Xmin SB[nBits] X minimum position for rect
#Xmax SB[nBits] X maximum position for rect
#Ymin SB[nBits] Y minimum position for rect
#Ymax SB[nBits] Y maximum position for rect
binary scan $rect B* bin_rect
set end 4
set start 0
set nbit 0
foreach char [split [string range $bin_rect $start $end] ""] {
  set nbit [expr {($nbit << 1) + $char}]
}

for {set i 0} {$i<4} {incr i} {
  set start [expr {$end+1}]
  set end [expr {$end+$nbit}]
  switch $i {
    0 {
      set xmin 0
      foreach char [split [string range $bin_rect $start $end] ""] {
        set xmin [expr {($xmin << 1) + $char}]
      }
    }
    1 {
      set xmax 0
      foreach char [split [string range $bin_rect $start $end] ""] {
        set xmax [expr {($xmax << 1) + $char}]
      }
    }
    2 {
      set ymin 0
      foreach char [split [string range $bin_rect $start $end] ""] {
        set ymin [expr {($ymin << 1) + $char}]
      }
    }
    3 {
      set ymax 0
      foreach char [split [string range $bin_rect $start $end] ""] {
        set ymax [expr {($ymax << 1) + $char}]
      }
   }
  }
}

set dimensions(width) [expr {($xmax-$xmin)/20}]
set dimensions(height) [expr {($ymax-$ymin)/20}]
return [array get dimensions]

 

Movie review: Passengers

Trailer

Finally decided to give this movie a try. It offers opulent and truly creative sci-fi visuals, Jennifer Lawrence and Chris Pratt trapped in what is supposed to be a romance setting in outer space, that’s about everything that is good about this movies summed up in one sentence.

The biggest issue with this movie: It cannot really decide what it wants to be. We have moments of utter abandonment in outer space ( the drama part ), attempts at the obvious romance ( the romance part ) and later some heroic action ( the action part ). Neither of them are convincing and fall short of their possibilities.

Here’s the plot: An engineer on a spaceship travelling to a distant planet is accidentally resurrected from long-distance travel stasis by a malfunctioning system and discovers that he is the only human being on the ship who came out of stasis, and that 90 years too early.

It is easy to comprehend that his reaction is pure and unfiltered despair. Getting back to sleep is impossible and his only company is the robotic bartender. The camera follows him wandering around the ship, enjoying all of its luxuries while still yearning for human company and slowly turning into a complete slob with a castaway-style beard.

This part of the movie could be exploring the human condition and cosmic loneliness, but no, no insightful philosophical monologues, no plans except for trying to smash the door to the bridge, just an average guy slowly degrading into a total slob.

Then he discovers sleeping beauty Aurora and develops an unhealthy obsession, reading her files and believing he has found the perfect woman without ever explaining why? Strangely enough, he does not care at all about the other 5000 passengers.

By now the next steps he will take should be obvious to the viewer and we get transported directly from the despair part to the romance part. If you thought the first part was wasting its potential, you will agree that the romance part is equally bad.

The creepy side of the guy is never explored, which might have more interesting than boring the audience with the intricacies of courting. Their love abruptly metamorphoses into hate as the robotic bartender tells her the truth. But then, we still get no real drama, some superficial tears, broken hearts etc but not more.

Then enters the action part: Something in the ship is broken and they have to fix it or face inevitable annihilation. Well, nothing to add here. Why all the red light on a spaceship when an alarm goes off? Is it one of the unwritten rules of the sci-fi genre or just careless imitation? Who cares.

Then there is an ending. A really bad ending: The guy saves the spaceship, finally dies and the girl brings him back to life by mashing all the buttons of the medical tube. Now that the guy has come back to life, all his misdeeds are forgiven and love enters the stage again. Congratulations, he finally got away with his plan. They lived happily ever after, never touching the dark side of their relationship again.

There is one thing missing completely from the whole movie: depth. Everything, the characters, their dialogs, their actions are shallow and artificial. Well, one can enjoy the visuals and the acting, but this still does not compensate for the messed up plot and the cheesy dialoges.

My verdict: 3 stars out of 5. Watch it, if you are a genre enthusiast or die-hard fan of one of the actors. If not, stay away from it.