How to drag rewind and fast-forward into the 21st century

This article originally appeared on earthli News and has been cross-posted here.

The most difficult technical problems to solve are the ones that you don't notice. The workflow and tools to which you've become accustomed are terrible, but they're so ingrained that you might actually find yourself unthinkingly defending them because that's just how it has to be.

Below I take a shot at designing a better user experience for a common feature: rewinding or fast-forwarding a video recorded on a DVR.

Why is your DVR's fast-forwarding feature stuck in the past?

Fast-forwarding and rewinding digital movies is one of those things.

Many people have DVRs now -- provided, often enough, by the cable company itself -- but they often function as if customers were still juggling tapes instead of switching between files on a hard drive. While there is no technical hurdle to making this process better, I acknowledge that there are probably very important albeit tediously prosaic advertising reasons for keeping fast-forwarding not just primitive, but almost deliberately broken.

Despite the strong likelihood that this feature will not be improved for the reasons stated above (i.e. that the exorbitant monthly fee that you pay for your content will continue to be supplemented by advertising revenue generated by your captive eyeballs), it would still be fun to imagine how we could make this feature better.

Use cases

The most obvious use case for fast-forwarding is to skip commercials in recorded content: that's just reality. Though the cable companies and networks would dearly love for everyone to take their medicine and watch all of their advertisements, users would dearly love to just watch their content without the ads. That is often the reason that they recorded the content in the first place.

Another use case is to scrub forward in longer sports events, like cycling or the Olympics. The user generally doesn't want to watch six hours; instead, the user would like to skip forward 2.5 hours, watch 15 minutes, skip another hour, watch 30 minutes, skip another hour and watch the rest, all the while skipping commercials in between. Often the user doesn't even know how far they want to skip; they need to see the content at various intervals in order to see where to stop. This is currently achieved by just scrubbing through all the content sequentially.

This is all not only a tedious amount of work but also takes much longer than necessary: even at the top speed, the fast-forward feature takes long minutes to skip two hours of content. This is ridiculous, especially when most of us have seen it work at least marginally better on a computer, where one can skip large chunks of content and reliably jump to a specific position in the recording. The system described below could improve the experience for computer-based media players as well.

What's the problem?

Fast-forwarding is a pain because, while you'd like to jump forward as quickly as possible, you have to be fast enough to stop it before it's gone too far. This is old-school technology from the days of the VCR when there was only one read-head per device. Now there's a digital file that the machine can easily read and render thumbnails from anywhere in the data stream.

My media box from UPC Cablecom offers the standard controls for scrubbing: play, pause, fast-forward, rewind. When you press rewind or fast-forward, it moves between five speeds, skipping forward or backward faster with each level. When you've got it on 5 of 5, you skip commercials or content very quickly, but you're also extremely likely to skip over content you wanted to watch.

The standard pattern is to fly forward, slam on the brakes, then backtrack slowly, overshoot again -- but not by as much -- and then finally position the read-head about where you want it, watching the final 20 seconds of commercials or station identification that you couldn't avoid until you finally get to the content you were looking for.

There has to be a better way of doing this.

Making it better

The idea of five speeds is fine, but we should be able to take the twitch-gamer component out of the experience. And this is coming from someone who used to be a pretty dedicated gamer; I can't imagine what this system feels like to someone unaccustomed to technology. They probably just put it on the slow speed -- or don't bother fast-forwarding at all.

What about a solution that works like this: instead of changing speed immediately, pressing rewind or fast-forward pauses the stream and switches to a scrubbing mode. The scrubbing mode is displayed as a screen of tiles -- say 5x5 -- each tile representing a screenshot/thumbnail from the stream that you're watching.

The thumbnails are chosen in the following manner. If you pressed fast-forward, the thumbnail for your current position is shown in the upper left-hand corner. Subsequent tiles are chosen at 5-second intervals going forward in the stream. Pressing the fast-forward again increases the level -- as before -- but, instead of speeding through the stream, it simply chooses new thumbnails, this time at 10-second intervals. Press again to switch to 30-second, then 1-minute, then 5-minute intervals. At the top "speed" the bottom right-hand corner shows a thumbnail 24 x 5 minutes forward in the stream.

Rewind has the same behavior, except that the current position is shown in the bottom right-hand corner and thumbnails proceed from right-to-left, bottom-to-top to show the user data in the stream before that position.

Once the user is on this screen, he or she can use the cursor to select the desired thumbnail and refocus the screen on that one by clicking OK. In this way, the user can quickly and reliably use the fast-forward or rewind buttons to switch the granularity to "home in" in on a particular scene. All without any stress, missteps or a lot of senseless back-and-forth scrubbing. And all without having to watch hardly anything -- a few seconds at most -- that the user doesn't want to watch.

When the right scene is selected (to within 5 seconds), the user presses play or pause to continue watching from the newly selected position.

Players like Roku have a "jump back ten seconds" feature that's quite useful, but the system described above makes that sound utterly primitive and limiting.

Going beyond five intervals

It is no longer necessary to have only 5 fixed intervals either. Perhaps the default interval (user-configurable) is 2 seconds, but that's only the center of a scale with 10 steps, so the user can drop down to 1-second or 1/2-second increments as well.

Positioning the current scene in scrubber mode

The system described above moves the default location of the current scene, depending on whether the user pressed rewind (bottom-right corner) or fast forward (top-left corner). Another approach would be to ignore which button was pressed and to always show the current scene in the center of the grid, with thumbnails showing history as well as future in the recording. Further presses of rewind and fast forward increase or decrease the amount of time represented by each thumbnail.

Rendering thumbnails

If the software takes time to render the thumbnails, it can do it asynchronously, rendering thumbnails to screen as they become available. Showing the time under the thumbnail would be massively helpful even without a thumbnail. The user could easily jump ahead 4 minutes without any adrenalin at all.

This should be a huge problem, though. Whenever the user opens a recording, the software can proactively cache thumbnails based on expected usage or default settings.

Learning HTML5 basics

We recently put together a list of links and references that would be useful for anyone interested in getting up to speed on HTML5 development. These are what we consider to be the absolute basics -- what you need in order to even begin discussing more complex issues of architecture, tiering, data-binding, MVC and so on. So, imagine you are participating in an HTML5 course at Encodo -- you'd probably get something like the following article in order to make sure you're ready.

HTML5 prerequisites

This section describes the knowledge prerequisites for course participants.

Since the course includes a significant hands-on component and will discuss the advantages and disadvantages of architecture-level concepts, a minimum level of proficiency in some basic topics is required.

  • Prerequisites include online resources that can be used to gain the minimum required level of proficiency. The resources are there to help participants learn about a topic. Participants that are already familiar with a topic do not need to use them.
  • Familiarity means I know what CSS selectors do and know a few of the basic ones. It does not mean I know every CSS selector by heart nor does it mean I read an article about CSS five years ago. Participants are expected to judge their own proficiency honestly and prepare accordingly.
  • Required resources are generally a few pages that can be read in 1015 minutes. Optional resources are helpful for learning more but arent required reading.


The DOM (Document Object Model) is the data structure on the client side that is rendered in the browser. A participant must be familiar with the basic tags and structure of the DOM as well as common attributes and events, including which ones are new to and deprecated in HTML5.




Participants must be familiar with the basic syntax and units. A working knowledge of how the basic selectors are applied to elements in the DOM is also required. Knowing how style cascade and override other styles (specificity rules) is a plus.




It is assumed the participants will be proficient in at least one programming language. An awareness of the common pitfalls and quirks of JavaScript is required: that it is untyped, has a very loose definition of objects and inheritance, and that web apps written in it tend to be quite functional and event-based in nature.




jQuery is an industry-standard library that binds HTML, CSS and JavaScript. Participants should be know how to use jQuery selectors use a CSS-like syntax to select elements from the HTML DOM, attach events to those elements and traverse to other elements in the DOM (e.g. children, siblings, etc.).



Browser compatibility

All modern browsers support the basic features outlined in the sections above. The site is useful to for finding out on which browsers the more advanced features are supported.

Practice sites

The following sites provide online sandboxes where participants can enter HTML, CSS and JavaScript to test it without installing or executing anything. They all allow examples to be saved for sharing.

A list of lesser-known OS X keyboard shortcuts

This article originally appeared on earthli News and has been cross-posted here.

The post Please share your hidden OS X features or tips and tricks yielded a treasure trove of keyboard shortcuts, some of which I knew and many that I'd never heard of or had long ago forgotten.

I collected, condensed and organized the ones I found the most useful below.

Finder & Open/Save dialogs

  • (-cmd) + (-shift) + G shows a location bar where you can type a path (/ or ~ also works in Open/Save). This text field supports ~ for the home directory and has rudimentary tab-completion.
  • (-cmd) + R reveals the currently selected item in a new Finder window.
  • (-cmd) + (-opt) + L selects your ~/Downloads folder.
  • (-cmd) + (-shift) + > shows/hides hidden files and folders (Open/Save dialogs only).
  • Dragging and dropping a file or folder into an Open/Save window re-targets that window on that file or folder

Managing applications

  • Press (-cmd) + tab to cycle through open applications.
  • Press (-cmd) + ~ (or < depending on keyboard layout) to cycle through open windows in the currently selected application.
  • While cycling, you can press q to quit the highlighted application or h to hide it
  • Press (-cmd) + (-opt) + esc to show a dialog that lets you force unresponsive applications to quit (you can even relaunch the Finder)
  • Hold down (-cmd) while clicking a dock icon to reveal that application in the Finder

Managing your Mac

  • Hold down (-opt) while clicking the "apple" menu on the top-left to execute commands (e.g. "Log out", "Shut down") without a confirmation dialog
  • Press ctrl + (-cmd) + (-opt) + (-eject) to shut down
  • Press (-cmd) + (-opt) + (-eject) to put the computer to sleep
  • Press ctrl + (-shift) + (-eject) to put the display to sleep
  • Press ctrl + (-cmd) + (-eject) to restart


  • (-cmd) + (-shift) + 4 lets you select an area to highlight and saves the screenshot to the desktop
  • (-cmd) + (-shift) + 4 + space lets you select an entire window, the dock, menu bar, etc. This will also include the drop shadow with transparency in the PNG screenshot.
  • Hold down ctrl with either of these to copy to the clipboard instead

Volume controls

  • Hold down (-shift) while adjusting the volume to mute the volume-changing sound (useful when adjusting volume during a call).
  • Hold down (-shift) + (-opt) while adjusting the volume to adjust in quarter-increments.
  • Hold down (-opt) while clicking the "sounds" menu-bar item to show a menu that lets you select the input/output devices without opening preferences

Screen & Brightness

  • Hold down (-shift) + (-opt) while adjusting the brightness to adjust in quarter-increments.
  • Hold down ctrl while scrolling with two fingers or the mouse wheel to zoom in/out on the entire screen
  • Hold down (-opt) while clicking the "bluetooth" or "wi-fi" menu-bar items to show a menu with more details about your connection, including options to show/generate diagnostics.
  • Hold down (-opt) while clicking the "notifications" icon to toggle it on/off
Including PDF in web sites

At first glance, this seems to be a pretty easy topic since PDFs are everywhere and can be found in almost every bigger website. But in most cases, PDF files are just linked for download and not embedded directly in the site. If the user clicks such a link, the browser decides what to do with the file: Just download to the file system or display a preview in a new tab or window. This also works pretty well for mobile devices since there are PDF readers for almost every platform.

But what if we want more than this, like embedding the document in the website and jumping to a specific page? The first part of this is very easy: We can use an iframe and set the location to the URL of the PDF.

<iframe src="document.pdf"></iframe>

This works fine on a desktop browser like chrome as it fits the width of the PDF to the width of the iframe:


But when we open the same page in mobile safari, it looks like following:


The PDF is not scaled and much worse: You can not even drag the document around. In short: This form of embedding PDF in websites is completely useless on iOS. Investigating deeper on this, it turns out that there is no way to fix this issue with a pure HTML / CSS solution.

Another solution that is worth looking at is pdf.js originally intended as a Firefox plugin to display PDF files in a platform-independent way. It renders PDF files into canvas elements using nothing more than pure JavaScript. In the hope that this will fix our PDF problem, we tried to include this JavaScript library in our web application. This worked fine for small- to medium-sized PDF files in desktop browsers as well as on mobile safari. But when we tried to display PDFs with complex content or more than 100 pages, we quickly ran into some limitations of this library: The rendering of huge PDFs was painfully slow and failed completely in some cases. I personally like this approach as it provides a platform independent solution which can be easily included in web applications, but it seems that it's just not ready right now. But maybe in a couple of months or years, this will be the way to go for displaying PDFs in web applications.

Another approach to fix this is to convert each page of the PDF into a PNG image. This approach is used widely on the web; for example by google books for the preview function. This approach is technically easy and things like zooming or jumping directly to a specific page can be implemented with a couple of lines of JavaScript. But one of the big drawbacks is that text is not submitted as text but as an image. This increases the transferred data size significantly which is, on the other hand, bad for mobile devices with their typically low bandwidth. To address this there are techniques like using the offline-application cache, which should definitely be kept in mind when using this approach.

After many hours investigating this topic, we ended up using the approach to include single pages of the PDF as PNG images in our web application. This requires that the PDF files be prepared server-side. Also, we implemented a dynamic-load algorithm which loads the images only when they are visible on the screen. This allowed us to display big documents without overburdening the video memory or the bandwidth of the mobile device.

v1.9.1: Bug fixes for 1.9 -- WAN speed, deadlocks and connection pooling

The summary below describes major new features, items of note and breaking changes. The full list of issues is also available for those with access to the Encodo issue tracker.


  • QNO-4201: Improved WAN speed by adding connection-pooling to avoid high connection setup costs
  • QNO-4233, QNO-4239, QNO-4241: Fixed some deadlock and connection-exhaustion issues in more complex models/data structures
  • QNO-4260: Upgraded DevExpress component library to v13.1
  • QNO-4246, QNO-4247: Made several improvements to object-graph management to improve identity/reference handling
  • QNO-4270, QNO-4278: Made some schema-migration improvements to support more conversions and constraint/path types

Breaking changes

  • Removed RemoteMethodCallException and added CreatePayloadException
Ignoring files with Git

This article originally appeared on earthli News and has been cross-posted here.

The helpful page, Ignoring files, taught me something I didn't know: there's a file you can use to ignore files in your local Git repository without changing anyone else's repository.

Just to recap, here are the ways to ignore a file:

  • Global .gitignore: you can designate basic exclusion directives that apply to all repositories on your system. This file is not committed to any repository or shared with others. Execute git config --global core.excludesfile ~/.gitignore_global to set the file to ~/.gitignore_global (for example). See the linked article for sample directives.
  • Per-repository global exclusions: add directives to the .git/info/exclude file in any repository. These directives are combined with any system-global directives to form the base exclusions for that repository. This file is not committed with the repository. This is the one I'd never heard of before.
  • .gitignore: add a file with this name to any directory. The directives in that file are merged with those from the parent directory to define the patterns that are excluded in that directory and all child directories. This is definitely the most common way to exclude files.
  • Exclude versioned files: and, finally, if your repository has files that are changed but not committed (e.g. configuration files), you can ignore future changes to those files with a call to git update-index --assume-unchanged path/to/file.txt. While this can be useful for legacy projects, it's best to structure new projects so developers don't have to rely on easily forgotten tricks like this.
Some new CSS length units (and some lesser-known ones)

This article originally appeared on earthli News and has been cross-posted here.

I've been using CSS since its inception and use many parts of the CSS3 specification for both personal work and work I do for Encodo. Recently, I read about some length units I'd never heard of in the article CSS viewport units: vw, vh, vmin and vmax by Chris Mills.

  • 1vw: 1% of viewport width
  • 1vh: 1% of viewport height
  • 1vmin: 1vw or 1vh, whatever is smallest
  • 1vmax: 1vw or 1vh, whatever is largest

These should be eminently useful for responsive designs. While there is wide support for these new units, that support is only available in the absolute latest versions of browsers. See the article for a good example of how these can be used.

While the ones covered in the article are actually new, there are others that have existed for a while but that I've never had occasion to use. The Font-relative lengths: the em, ex, ch, rem units section lists the following units:

  • em: This one is well-known: 1em is equal to the "computed value of the 'font-size' property of the element on which it is used."
  • ex: Equal to the height of the letter 'x' in the font of the element on which it is used. This is useful when you want to size a container based on the height of a lower-case letter -- i.e. tighter -- rather than on the full size of the font (as you get with em).
  • ch: "Equal to the advance measure of the "0" (ZERO, U+0030) glyph found in the font used to render it." Since all digits in a font should be the same width, this unit is probably useful for pages that need to measure and render numbers in a reliable vertical alignment.
  • rem: The same as em but always returns the value for the root element of the page rather than the current element. Elements that use this unit will all scale against a common size, independently of the font-size of their contents. Theres more to the CSS rem unit than font sizing by Roman Rudenko has a lot more information and examples, as well as an explanation of how rem can stand in for the still nascent support for vw.
A rant in Ominor (the decline and fall of the Opera browser)

This article originally appeared on earthli News and has been cross-posted here.

Opera has officially released their first desktop browser based on the Blink engine (forked from WebKit). The vision behind Opera 15 and beyond by Sebastien Baberowski explains how Opera 15... dead on arrival.1

Choose your market

For years, Opera has held a steady 1.7--2% of the desktop browser market. This seems small but comprises dozens of millions of users. More capitalist heads have clearly prevailed at Opera. They've struck out for a more lucrative market. Instead of catering to the 2% of niche, expert users that were die-hard, loyal fans, they will create a clone of Chrome/Firefox/Safari that will cater to a much, much wider market.

In terms of fiscal reasoning, it's not hard to see why they're going in this direction. They will abandon their previous user base -- the hardcore market -- to the thankless chore of downloading and configuring their browsers with buggy extensions that offer half-implemented versions of the features that used to be high-performance and native.

As one such user, I am saddened, but am also almost certain that there is no turning back.2 It's been a good run, though. The browser market will be quite homogenized, but perhaps some enterprising open-source project will take up the flame and build us a better Opera.

Here's how another user put it in the comments for the article,

Opera's main reason was not to spend their time on browser innovation, but to save money. Opera became misinformative, untrustworthy company, disrespectful towards long-time and power users, whose disappointment Opera now tries to appease by extensions and "future" features.

That has been my impression, as well.

Opera does too have features!

Though many of the features that defined Opera for its users are gone -- perhaps to be resurrected -- the company goes out of its way to trumpet its innovation in this latest incarnation of its browser.

The article lightly covers the same four features that they won't shut up about -- Speed Dial, Stash, Discover and Off-road Mode -- and tells loyal Opera users that if "you find that Opera 15 doesnt have a feature you depend upon, first check the growing list of extensions". In other words, Opera is now just Chrome without Google? All of the out-of-the-box features that Opera users have come to expect have just been deep-sixed? And we can all hold out hope that the community develops them for Opera? And we get to spend a ton of time evaluating, downloading, testing and setting up these extensions?

I can "discover" the web just fine on my own without Opera's help. This feature feels more like an AOL/Facebook/Google+ crutch to get me to read catered content. Where's the pro version of the Opera browser? I'm browsing on a desktop with a 150Mb Internet connection -- Off-road Mode is utterly useless for me. Just as Turbo was useless before.

Stash, the Process Model and Memory Hunger

And shall we guess why they're pushing Stash so hard? Because they want to train us to stop keeping so many tabs open. You see, keeping dozens and dozens of tabs open brings any browser other than Opera to its knees. Either that, or the browser soon takes over most of the resources of the machine on which it runs and brings the OS to its knees.

Now that Opera has inherited the process model from the Blink engine, well, they suffer from the same issues that Chrome has: it's just not very good at keeping dozens and dozens of tabs open. Kudos to Opera for at least recognizing the problem and trying to train its users to be more reasonable. It's a bit weird for Opera users to hear this, though, because that was one of the reasons we used their browser in the first place: it just worked and didn't make us change our work habits to accommodate the tool.

Next? Beta? Alpha.

The halcyon days of faster, better and slimmer are, apparently, gone. At least for now. Version 15, though it's called an official release, is, for an Opera user, not even a beta. It is, at best, an early alpha that is nowhere near feature-completeness.

I understand that you want to trim the fat: some non-browsing features can legitimately be moved to other apps or put to sleep. It's utterly arguable that a browser doesn't need it's own IRC client, an RSS reader, a mail client, something called Unite.

But intimating that "Fit to Width" is too confusing a feature and won't come back? Removing bookmarks? And sessions? And the whole "Reopen closed windows" feature? And replacing it all with a single-level Speed Dial and something called Stash? And, of course...

The article goes on to cheerfully explain that there is a bookmark manager extension. This extension comes from Opera itself and is the official recommendation from the press release/article linked above. The first few comments should be enough to scare off anyone. This isn't too surprising: the bookmark manager in Opera 12 was barely adequate and had seen little love for years. But it worked. It had folders.3 It synced via Opera Link.

All that is gone. Use Stash instead.

Oh, and anything you configure will be local to that machine until Opera Link is reactivated. No roadmap for that yet. No roadmap for anything, in fact. Just a bunch of promises that "we are looking at your comments and feedback". There's nowhere to actually register that feedback and see whether Opera's considering it (something like Microsoft's "User Voice" would be nice). I can't believe I just wrote that I wish Opera would be more like Microsoft in engaging with the community.

Who thought this was a good idea? Hey, maybe there's an extension for Opera Link? Maybe I can cut&paste my browser together from dozens of extensions? Isn't that why I was using Opera instead of another browser? And even were I to do this, I get to repeat this configuration on absolutely every machine on which I use Opera guessed it: Opera Link is gone, so I don't get any data-synchronization anymore. Not for bookmarks (which are gone anyway) but also not for the Wand (which is gone anyway)4 and certainly not for extensions, which were never synced, even in Opera 12.x.5

How in the name of all that is holy is moving bookmarks to an extension a move that offers a "UI simple enough to be intuitive for a consumer who wants a solid, fast browser that just works"?

Well, of course everything just works -- your browser no longer has any features.

So the check list of features in Opera 15 consists of "show web pages" which comes free by including the Chromium project. Whoop-de-doo.

Wait and see

I can't believe I'm writing this because I've always upgraded to the latest version, but: you can stick Opera 15 where the sun doesn't shine; I'm sticking with Opera 12. I'm happy with that for now, but I know it's not a long-term -- or even medium-term -- solution. Sigh.

  1. Disclaimer: I've been using Opera since version 3.6. About ten years ago, I joined an early-tester program to help them build their Mac browser (for the egotistical reason that I wanted to use Opera on my Mac). I'm still enrolled in that program, though my participation is considerably less than it used to be.

  2. And no, the article Ctrl+Z of Ctrl+D by Krystian Kolondra, in which Opera backpedals and swears that they will restore native bookmarks, is far from reassuring. The product strategy is clear; a bit of backpedaling on one feature doesn't change very much.

  3. Even though you couldn't see the bookmark-folder hierarchy very well -- or at all on the Mac -- when selecting one in the drop-down.

  4. To be honest, I've long since moved on to LastPass because a browser-specific password solution was too limiting for my work.

  5. At least Google solved the customization problem to some degree by saving your extensions as part of your account and syncing them whenever you log in from somewhere. That's a good start. But many of the Chrome extensions are pale imitations of the classic Opera features so Chrome is at best a partially satisfactory fallback position.

v1.9: Plugins, model overlays and more!

The summary below describes major new features, items of note and breaking changes. The full list of issues is also available for those with access to the Encodo issue tracker.


  • Plugins: You can now extend your Quino applications with plugins. The application can determine the locations from which plugins are loaded but the default behavior is to load plugin assemblies from a folder next to the executable as well as from a folder in the user's local configuration folder. Also by default, if the application is running in debug mode, C# files in those directories are compiled and loaded as plugins as well. This allows developers or demonstrators in the field to update the metadata without using Visual Studio to recompile the application.
  • Software Update: The software updater component now supports HTTP as well as file-shares and downloads the file locally before executing it, showing download progress for slower connections or larger updates.
  • Remoting Routes: QNO-4060: Routes/URLs on the remote server are now resolved using a registry of route handlers. An application is free to replace or enhance the standard route handlers or add new ones. Testing support remoting has been improved (i.e. configuration of a loopback remoting server has been vastly simplified and encapsulated in a RemoteTextMixinBase).
  • Data sources: QNO-4048, QNO-3628, QNO-4034, QNO-4037, QNO-4051, QNO-4139, QNO-4140, QNO-4071: Multiple remote data sources are now supported throughout the configuration, startup, login and application.
  • Optimistic locking: QNO-4049: Added aspects to include optimitic-locking support for meta-classes
  • Change tracking: QNO-4050: Added aspects to include change-tracking support for meta-classes
  • Model names: QNO-4152, QNO-4156: Improved support for models with long(er) names (in particular, schema migration now works as expected)
  • VS Project template: QNO-4149, QNO-4150, QNO-4151: Improved the Quino project/solution Visual Studio 2012 template
  • Error messages: QNO-4081, QNO-4166: Improved error messages for data-source errors and improved the API for formatting error user-facing messages
  • Remoting Driver: QNO-4075, QNO-4080, QNO-4068, QNO-4060, QNO-4059, QNO-4056, QNO-4037: Made many improvements and optimizations to the remoting data driver
  • Caching: QNO-140, QNO-3809, QNO-3808: Made several improvements to caching API, including new default providers for the default DataCache.
  • Many-to-many Relations: QNO-4219: Added a QueryAspect to show read-only views of many-to-many relations
  • Object comparison: QNO-4027: GenericObject should be comparable to other GenericObjects or PK values

Breaking changes

  • QNO-4026: IMetaReadable.GetValue() behavior is inconsistent with relations and methods. The behavior or reading a related object or list using GetValue() has changed. Previously, the value returned non-null only if it had been caused to load by using GetObject() or GetList()) or if it had a ValueGenerator. If it was generated with a ValueGenerator, it was always regenerated, ignoring the value of ValueGenerationFrequency.
  • QNO-4028: GenericObject should behave correctly when adding to a HashSet. Previously, the hash-code generated for GenericObjects was not well-matched to the result of the Equals() method, which resulted in unpredictable behavior with hash tables, sets or dictionaries. This has been fixed, but applications that relied on the formerly unpredictable behavior will now function differently.
  • The enum DatabaseState no longer exists. It has been replaced with ExternalResourceState.
  • The IAuthenticator<TApplication>, IAuthorizer<TApplication> and ILoginValidator<TApplication> interfaces have all acquired a method with interface void LoadSettings(TConfiguration configuration, IMessageRecorder recorder).
  • Encodo.Data.SessionFlags have been moved to Encodo.Quino.Data.Persistence.SessionFlags
  • The signature of ICoreConfiguration.GetConnectionDetails()no longer returns a simple string, but a sequence of strings. To restore , use string.Join("; "_configuration.GetConnectionDetails())
  • EnryptionType was moved from Encodo.Security to Encodo.Encryption
  • DirectoryServiceSettings.ServerUri is deprecated; use HostName instead.
  • MetaBuilderModuleTools has been renamed to MetaBuilderTools.
  • MetaBuilderBasedMetadataGeneratorBase.ConfigureBuilder() no longer exists; instead, override MetaBuilderBasedMetadataGeneratorBase.RegisterDependencies().
  • MetaBuilder.AddMultiLanguageProperty() now requires a base Guid parameter.
  • MetaBuilder.AddWrapperClass() no longer requires a Guid parameter
The HTML5 AppCache and HTTP Authentication

The following article outlines a solution to what may end up being a temporary problem. The conditions are very specific: no server-side logic; HTTP authentication; AppCache as it is implemented by the target platforms -- Safari Mobile and Google Chrome -- in late 2012/early 2013. The solution is not perfect but it's workable. We're sharing it here in the hope that it can help someone else or serve as a base for a better solution.

The HTML5 AppCache

The application cache is a relatively new feature that is,

  • Supported by all modern browsers
  • Uses a manifest file that indicates which files to cache
  • Browser checks manifest for changes
  • If there are changes, all files are refreshed
  • External links work when online
  • When offline, the application works with the local cache
  • External links to non-cached content are redirected to fallback links

AppCache Limitations

Web applications can use the HTML5 application-cache to store local content, but different browsers apply different restrictions to the amount of space allocated per domain.

  • Safari Mobile is limited to 50MB per domain. This means that the restriction will generally apply to all content packages downloaded from the same server/domain
  • Google Chrome is limited as well, but the actual limit is a bit of a moving target

Optimizing the HTML5 AppCache for Authenticated Content

In particular, the Safari Mobile browser cannot update the application cache for files for which it must obtain authentication.

  • Some requests do not trigger authentication
    • Manifest file
    • Home-screen icons
  • A lost connection or timeout can invalidate the authentication token
  • Version checks are not reliable
    • Open pages/running apps do not check for status updates
    • Home-screen apps dont reliably check on startup
    • This can lead to out-of-date or missing content

Checking for and presenting updates to the user

The graphic below illustrates the mechanism by which a content package in a web application can manage content updates and present them to the user.

  • When online, the software regularly checks whether an update for the package is available
  • The user can determine whether to install an update
  • When an update has been found, the software stops checking for updates until the user has applied the latest update
  • If the user delays the update, the user interface displays an update button
  • The software will automatically start checking for updates whenever it detects that it is online
  • There is no way for a user to ignore updates
  • When the user proceeds with an update, the latest version is retrieved at that time, ensuring that the user has the latest version


Solving the problems with authenticated data and the AppCache

In order to address the problems described above, the application uses a separate version file to check for updates independent of the browsers application-cache mechanism and to trigger this update only when authentication has been reestablished.


  • The cache.version.txt file is publicly available but is very small and includes only a unique version number that is also included in the cache.manifest file (both of which are generated by a deployment script).
  • The software compares this version number against the last known good version number. If it differs, it knows that the server has been updated with new content for this package
  • Before the software can kick off the HTML5 AppCache update process, it must ensure that the user is authenticated and authorized to retrieve the update package (because most browsers will simply fail silently if this is not the case).
  • The software pulls the force.password.txt file from the private zone with an explicit request. The browser will ask the user to authenticate, if necessary. This file is also very small to avoid needlessly downloading a large amount of data simply to force re-authentication.
  • Once the user has authenticated, the software lets the automated HTML5 AppCache update take over, retrieving first the cache.manifest file and then updating files as needed. The user is notified that this download is taking place asynchronously.
  • The software receives a notification from the browser that the update is complete and can record the version number and then notify the user that the update has been applied and is ready to use.

This approach worked relatively well for us, although we continue to refine it based on feedback and experience.