[pytango] 305/483: changes to documentation

Sandor Bodo-Merle sbodomerle-guest at moszumanska.debian.org
Thu Sep 28 19:14:53 UTC 2017


This is an automated email from the git hooks/post-receive script.

sbodomerle-guest pushed a commit to annotated tag bliss_8.10
in repository pytango.

commit daf42a4cead1ca12fdbe72349c07e2b1f49c9498
Author: tiagocoutinho <tiagocoutinho at 4e9c00fd-8f2e-0410-aa12-93ce3db5e235>
Date:   Tue Nov 19 07:37:21 2013 +0000

    changes to documentation
    
    git-svn-id: http://svn.code.sf.net/p/tango-cs/code/bindings/PyTango/trunk@24253 4e9c00fd-8f2e-0410-aa12-93ce3db5e235
---
 doc/_static/banner.png                             |  Bin 427830 -> 0 bytes
 doc/_static/banner1.png                            |  Bin 0 -> 335135 bytes
 doc/_static/banner2.png                            |  Bin 0 -> 53657 bytes
 doc/_static/boost_python_install.py                |   43 +-
 doc/_static/galleria/LICENSE                       |   21 +
 doc/_static/galleria/galleria-1.3.2.js             | 6990 ++++++++++++++++++++
 doc/_static/galleria/galleria-1.3.2.min.js         |    3 +
 .../galleria/themes/classic/classic-demo.html      |  124 +
 .../galleria/themes/classic/classic-loader.gif     |  Bin 0 -> 1849 bytes
 .../galleria/themes/classic/classic-map.png        |  Bin 0 -> 1123 bytes
 .../galleria/themes/classic/galleria.classic.css   |  219 +
 .../galleria/themes/classic/galleria.classic.js    |  101 +
 .../themes/classic/galleria.classic.min.js         |    1 +
 doc/_static/galleria_index.css                     |   10 +
 doc/_static/galleria_index.js                      |   14 +
 doc/_templates/index.html                          |   92 +-
 doc/_templates/layout.html                         |   13 -
 doc/conf.py                                        |   11 +-
 doc/server/index.rst                               |    2 +-
 doc/server/{hlapi.rst => server.rst}               |   24 +-
 doc/utilities.rst                                  |    2 -
 21 files changed, 7543 insertions(+), 127 deletions(-)

diff --git a/doc/_static/banner.png b/doc/_static/banner.png
deleted file mode 100644
index 67ec30d..0000000
Binary files a/doc/_static/banner.png and /dev/null differ
diff --git a/doc/_static/banner1.png b/doc/_static/banner1.png
new file mode 100644
index 0000000..75ae5d5
Binary files /dev/null and b/doc/_static/banner1.png differ
diff --git a/doc/_static/banner2.png b/doc/_static/banner2.png
new file mode 100644
index 0000000..c60e785
Binary files /dev/null and b/doc/_static/banner2.png differ
diff --git a/doc/_static/boost_python_install.py b/doc/_static/boost_python_install.py
index 893dd43..381b219 100644
--- a/doc/_static/boost_python_install.py
+++ b/doc/_static/boost_python_install.py
@@ -1,7 +1,15 @@
-from __future__ import print_function
+# ------------------------------------------------------------------------------
+# This file is part of PyTango (http://www.tinyurl.com/PyTango)
+#
+# Copyright 2006-2012 CELLS / ALBA Synchrotron, Bellaterra, Spain
+# Copyright 2013-2014 European Synchrotron Radiation Facility, Grenoble, France
+#
+# Distributed under the terms of the GNU Lesser General Public License,
+# either version 3 of the License, or (at your option) any later version.
+# See LICENSE.txt for more info.
+# ------------------------------------------------------------------------------
 
-"""
-*build boost python script on windows*
+"""*build boost python script on windows*
 
 Purpose
     Build boost-python on multiple architectures (32 and 64bits), with different toolsets (vc9, vc10),
@@ -15,21 +23,25 @@ How to use it
     This script should be used together with another boost configuration file called user-config.jam.
     
     - Download boost source code from http://wwww.boost.org
-    - Extract boost to a directory (ex: c:\workspace\boost-1.53.0)
-    - Place this file in your boost extract directory (ex: c:\workspace\boost-1.53.0\boost_python_install.py)
-    - Place the user-config.jam file in %HOMEPATH%%HOMEDIR%
+    - Extract boost to a directory (ex: :file:`c:\\workspace\\boost-1.53.0`)
+    - Place this file in your boost extract directory
+      (ex: :file:`c:\\workspace\\boost-1.53.0\\boost_python_install.py`)
+    - Place the user-config.jam file in :envvar:`%HOMEPATH%%HOMEDIR%`
     - Open a console
     - Switch to the boost directory 
-    - Execute this script using python (ex: C:\Python\win32\26\python.exe boost_python_install.py
+    - Execute this script using python
+      (ex: :file:`C:\\Python\\win32\\26\\python.exe boost_python_install.py`
 """
+
+from __future__ import print_function
+
+
 # b2 --with-python --prefix=c:\boost-1.53.0 
 #    --libdir=c:\boost-1.53.0\msvc-9.0\Win32\release\shared\threading-multi\26
 #    toolset=msvc-9.0 address-model=32 variant=release link=shared
 #    threading=multi python=2.6 install
 
 import os
-import sys
-import pprint
 import subprocess
 
 boost_version = r"1.53.0"
@@ -75,13 +87,10 @@ def _main():
     
     toolsets = r"msvc-10.0",
     pythons = "3.3",    
-    compile()
+    compile_boost()
         
-def compile():
-    cur_dir = os.path.abspath(os.path.curdir)
-    
+def compile_boost():    
     prefix = r"c:\boost-" + boost_version
-    build_prefix = os.path.join(prefix, "build")
     
     silent_args = ""
     if silent:
@@ -98,8 +107,8 @@ def compile():
     cmd_line_template = base_cmd_line
     for option in options:
         cmd_line_template += " --{0}={{{1}}}".format(option, option)
-    for property in properties:
-        cmd_line_template += " {0}={{{1}}}".format(property, property)
+    for prop in properties:
+        cmd_line_template += " {0}={{{1}}}".format(prop, prop)
     
     cmd_line_template += " {0}".format(stage)
     fh = open("NUL", "w")
@@ -152,4 +161,4 @@ def compile():
     fh.close()
     
 if __name__ == "__main__":
-    main()
\ No newline at end of file
+    main()
diff --git a/doc/_static/galleria/LICENSE b/doc/_static/galleria/LICENSE
new file mode 100644
index 0000000..4531e29
--- /dev/null
+++ b/doc/_static/galleria/LICENSE
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2013 Aino http://aino.se
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/doc/_static/galleria/galleria-1.3.2.js b/doc/_static/galleria/galleria-1.3.2.js
new file mode 100644
index 0000000..0dfe66a
--- /dev/null
+++ b/doc/_static/galleria/galleria-1.3.2.js
@@ -0,0 +1,6990 @@
+/**
+ * Galleria v 1.3.2 2013-11-04
+ * http://galleria.io
+ *
+ * Licensed under the MIT license
+ * https://raw.github.com/aino/galleria/master/LICENSE
+ *
+ */
+
+(function( $, Galleria, undef ) {
+
+/*global jQuery, navigator, Image */
+
+// some references
+var window = this,
+    doc    = window.document,
+    $doc   = $( doc ),
+    $win   = $( window ),
+
+// native prototypes
+    protoArray = Array.prototype,
+
+// internal constants
+    VERSION = 1.32,
+    DEBUG = true,
+    TIMEOUT = 30000,
+    DUMMY = false,
+    NAV = navigator.userAgent.toLowerCase(),
+    HASH = window.location.hash.replace(/#\//, ''),
+    PROT = window.location.protocol,
+    M = Math,
+    F = function(){},
+    FALSE = function() { return false; },
+    IE = (function() {
+
+        var v = 3,
+            div = doc.createElement( 'div' ),
+            all = div.getElementsByTagName( 'i' );
+
+        do {
+            div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->';
+        } while ( all[0] );
+
+        return v > 4 ? v : undef;
+
+    }() ),
+    DOM = function() {
+        return {
+            html:  doc.documentElement,
+            body:  doc.body,
+            head:  doc.getElementsByTagName('head')[0],
+            title: doc.title
+        };
+    },
+    IFRAME = window.parent !== window.self,
+
+    // list of Galleria events
+    _eventlist = 'data ready thumbnail loadstart loadfinish image play pause progress ' +
+                 'fullscreen_enter fullscreen_exit idle_enter idle_exit rescale ' +
+                 'lightbox_open lightbox_close lightbox_image',
+
+    _events = (function() {
+
+        var evs = [];
+
+        $.each( _eventlist.split(' '), function( i, ev ) {
+            evs.push( ev );
+
+            // legacy events
+            if ( /_/.test( ev ) ) {
+                evs.push( ev.replace( /_/g, '' ) );
+            }
+        });
+
+        return evs;
+
+    }()),
+
+    // legacy options
+    // allows the old my_setting syntax and converts it to camel case
+
+    _legacyOptions = function( options ) {
+
+        var n;
+
+        if ( typeof options !== 'object' ) {
+
+            // return whatever it was...
+            return options;
+        }
+
+        $.each( options, function( key, value ) {
+            if ( /^[a-z]+_/.test( key ) ) {
+                n = '';
+                $.each( key.split('_'), function( i, k ) {
+                    n += i > 0 ? k.substr( 0, 1 ).toUpperCase() + k.substr( 1 ) : k;
+                });
+                options[ n ] = value;
+                delete options[ key ];
+            }
+        });
+
+        return options;
+    },
+
+    _patchEvent = function( type ) {
+
+        // allow 'image' instead of Galleria.IMAGE
+        if ( $.inArray( type, _events ) > -1 ) {
+            return Galleria[ type.toUpperCase() ];
+        }
+
+        return type;
+    },
+
+    // video providers
+    _video = {
+        youtube: {
+            reg: /https?:\/\/(?:[a-zA_Z]{2,3}.)?(?:youtube\.com\/watch\?)((?:[\w\d\-\_\=]+&(?:amp;)?)*v(?:<[A-Z]+>)?=([0-9a-zA-Z\-\_]+))/i,
+            embed: function() {
+                return 'http://www.youtube.com/embed/' + this.id;
+            },
+            getUrl: function() {
+                return PROT + '//gdata.youtube.com/feeds/api/videos/' + this.id + '?v=2&alt=json-in-script&callback=?';
+            },
+            get_thumb: function(data) {
+                return data.entry.media$group.media$thumbnail[2].url;
+            },
+            get_image: function(data) {
+                if ( data.entry.yt$hd ) {
+                    return PROT + '//img.youtube.com/vi/'+this.id+'/maxresdefault.jpg';
+                }
+                return data.entry.media$group.media$thumbnail[3].url;
+            }
+        },
+        vimeo: {
+            reg: /https?:\/\/(?:www\.)?(vimeo\.com)\/(?:hd#)?([0-9]+)/i,
+            embed: function() {
+                return 'http://player.vimeo.com/video/' + this.id;
+            },
+            getUrl: function() {
+                return PROT + '//vimeo.com/api/v2/video/' + this.id + '.json?callback=?';
+            },
+            get_thumb: function( data ) {
+                return data[0].thumbnail_medium;
+            },
+            get_image: function( data ) {
+                return data[0].thumbnail_large;
+            }
+        },
+        dailymotion: {
+            reg: /https?:\/\/(?:www\.)?(dailymotion\.com)\/video\/([^_]+)/,
+            embed: function() {
+                return PROT + '//www.dailymotion.com/embed/video/' + this.id;
+            },
+            getUrl: function() {
+                return 'https://api.dailymotion.com/video/' + this.id + '?fields=thumbnail_240_url,thumbnail_720_url&callback=?';
+            },
+            get_thumb: function( data ) {
+                return data.thumbnail_240_url;
+            },
+            get_image: function( data ) {
+                return data.thumbnail_720_url;
+            }
+        },
+        _inst: []
+    },
+    Video = function( type, id ) {
+
+        for( var i=0; i<_video._inst.length; i++ ) {
+            if ( _video._inst[i].id === id && _video._inst[i].type == type ) {
+                return _video._inst[i];
+            }
+        }
+
+        this.type = type;
+        this.id = id;
+        this.readys = [];
+
+        _video._inst.push(this);
+
+        var self = this;
+
+        $.extend( this, _video[type] );
+
+        $.getJSON( this.getUrl(), function(data) {
+            self.data = data;
+            $.each( self.readys, function( i, fn ) {
+                fn( self.data );
+            });
+            self.readys = [];
+        });
+
+        this.getMedia = function( type, callback, fail ) {
+            fail = fail || F;
+            var self = this;
+            var success = function( data ) {
+                callback( self['get_'+type]( data ) );
+            };
+            try {
+                if ( self.data ) {
+                    success( self.data );
+                } else {
+                    self.readys.push( success );
+                }
+            } catch(e) {
+                fail();
+            }
+        };
+    },
+
+    // utility for testing the video URL and getting the video ID
+    _videoTest = function( url ) {
+        var match;
+        for ( var v in _video ) {
+            match = url && _video[v].reg && url.match( _video[v].reg );
+            if( match && match.length ) {
+                return {
+                    id: match[2],
+                    provider: v
+                };
+            }
+        }
+        return false;
+    },
+
+    // native fullscreen handler
+    _nativeFullscreen = {
+
+        support: (function() {
+            var html = DOM().html;
+            return !IFRAME && ( html.requestFullscreen || html.mozRequestFullScreen || html.webkitRequestFullScreen );
+        }()),
+
+        callback: F,
+
+        enter: function( instance, callback, elem ) {
+
+            this.instance = instance;
+
+            this.callback = callback || F;
+
+            elem = elem || DOM().html;
+            if ( elem.requestFullscreen ) {
+                elem.requestFullscreen();
+            }
+            else if ( elem.mozRequestFullScreen ) {
+                elem.mozRequestFullScreen();
+            }
+            else if ( elem.webkitRequestFullScreen ) {
+                elem.webkitRequestFullScreen();
+            }
+        },
+
+        exit: function( callback ) {
+
+            this.callback = callback || F;
+
+            if ( doc.exitFullscreen ) {
+                doc.exitFullscreen();
+            }
+            else if ( doc.mozCancelFullScreen ) {
+                doc.mozCancelFullScreen();
+            }
+            else if ( doc.webkitCancelFullScreen ) {
+                doc.webkitCancelFullScreen();
+            }
+        },
+
+        instance: null,
+
+        listen: function() {
+
+            if ( !this.support ) {
+                return;
+            }
+
+            var handler = function() {
+
+                if ( !_nativeFullscreen.instance ) {
+                    return;
+                }
+                var fs = _nativeFullscreen.instance._fullscreen;
+
+                if ( doc.fullscreen || doc.mozFullScreen || doc.webkitIsFullScreen ) {
+                    fs._enter( _nativeFullscreen.callback );
+                } else {
+                    fs._exit( _nativeFullscreen.callback );
+                }
+            };
+            doc.addEventListener( 'fullscreenchange', handler, false );
+            doc.addEventListener( 'mozfullscreenchange', handler, false );
+            doc.addEventListener( 'webkitfullscreenchange', handler, false );
+        }
+    },
+
+    // the internal gallery holder
+    _galleries = [],
+
+    // the internal instance holder
+    _instances = [],
+
+    // flag for errors
+    _hasError = false,
+
+    // canvas holder
+    _canvas = false,
+
+    // instance pool, holds the galleries until themeLoad is triggered
+    _pool = [],
+
+    // themeLoad trigger
+    _themeLoad = function( theme ) {
+
+        Galleria.theme = theme;
+
+        // run the instances we have in the pool
+        $.each( _pool, function( i, instance ) {
+            if ( !instance._initialized ) {
+                instance._init.call( instance );
+            }
+        });
+
+        _pool = [];
+    },
+
+    // the Utils singleton
+    Utils = (function() {
+
+        return {
+
+            // legacy support for clearTimer
+            clearTimer: function( id ) {
+                $.each( Galleria.get(), function() {
+                    this.clearTimer( id );
+                });
+            },
+
+            // legacy support for addTimer
+            addTimer: function( id ) {
+                $.each( Galleria.get(), function() {
+                    this.addTimer( id );
+                });
+            },
+
+            array : function( obj ) {
+                return protoArray.slice.call(obj, 0);
+            },
+
+            create : function( className, nodeName ) {
+                nodeName = nodeName || 'div';
+                var elem = doc.createElement( nodeName );
+                elem.className = className;
+                return elem;
+            },
+
+            removeFromArray : function( arr, elem ) {
+                $.each(arr, function(i, el) {
+                    if ( el == elem ) {
+                        arr.splice(i, 1);
+                        return false;
+                    }
+                });
+                return arr;
+            },
+
+            getScriptPath : function( src ) {
+
+                // the currently executing script is always the last
+                src = src || $('script:last').attr('src');
+                var slices = src.split('/');
+
+                if (slices.length == 1) {
+                    return '';
+                }
+
+                slices.pop();
+
+                return slices.join('/') + '/';
+            },
+
+            // CSS3 transitions, added in 1.2.4
+            animate : (function() {
+
+                // detect transition
+                var transition = (function( style ) {
+                    var props = 'transition WebkitTransition MozTransition OTransition'.split(' '),
+                        i;
+
+                    // disable css3 animations in opera until stable
+                    if ( window.opera ) {
+                        return false;
+                    }
+
+                    for ( i = 0; props[i]; i++ ) {
+                        if ( typeof style[ props[ i ] ] !== 'undefined' ) {
+                            return props[ i ];
+                        }
+                    }
+                    return false;
+                }(( doc.body || doc.documentElement).style ));
+
+                // map transitionend event
+                var endEvent = {
+                    MozTransition: 'transitionend',
+                    OTransition: 'oTransitionEnd',
+                    WebkitTransition: 'webkitTransitionEnd',
+                    transition: 'transitionend'
+                }[ transition ];
+
+                // map bezier easing conversions
+                var easings = {
+                    _default: [0.25, 0.1, 0.25, 1],
+                    galleria: [0.645, 0.045, 0.355, 1],
+                    galleriaIn: [0.55, 0.085, 0.68, 0.53],
+                    galleriaOut: [0.25, 0.46, 0.45, 0.94],
+                    ease: [0.25, 0, 0.25, 1],
+                    linear: [0.25, 0.25, 0.75, 0.75],
+                    'ease-in': [0.42, 0, 1, 1],
+                    'ease-out': [0, 0, 0.58, 1],
+                    'ease-in-out': [0.42, 0, 0.58, 1]
+                };
+
+                // function for setting transition css for all browsers
+                var setStyle = function( elem, value, suffix ) {
+                    var css = {};
+                    suffix = suffix || 'transition';
+                    $.each( 'webkit moz ms o'.split(' '), function() {
+                        css[ '-' + this + '-' + suffix ] = value;
+                    });
+                    elem.css( css );
+                };
+
+                // clear styles
+                var clearStyle = function( elem ) {
+                    setStyle( elem, 'none', 'transition' );
+                    if ( Galleria.WEBKIT && Galleria.TOUCH ) {
+                        setStyle( elem, 'translate3d(0,0,0)', 'transform' );
+                        if ( elem.data('revert') ) {
+                            elem.css( elem.data('revert') );
+                            elem.data('revert', null);
+                        }
+                    }
+                };
+
+                // various variables
+                var change, strings, easing, syntax, revert, form, css;
+
+                // the actual animation method
+                return function( elem, to, options ) {
+
+                    // extend defaults
+                    options = $.extend({
+                        duration: 400,
+                        complete: F,
+                        stop: false
+                    }, options);
+
+                    // cache jQuery instance
+                    elem = $( elem );
+
+                    if ( !options.duration ) {
+                        elem.css( to );
+                        options.complete.call( elem[0] );
+                        return;
+                    }
+
+                    // fallback to jQuery's animate if transition is not supported
+                    if ( !transition ) {
+                        elem.animate(to, options);
+                        return;
+                    }
+
+                    // stop
+                    if ( options.stop ) {
+                        // clear the animation
+                        elem.unbind( endEvent );
+                        clearStyle( elem );
+                    }
+
+                    // see if there is a change
+                    change = false;
+                    $.each( to, function( key, val ) {
+                        css = elem.css( key );
+                        if ( Utils.parseValue( css ) != Utils.parseValue( val ) ) {
+                            change = true;
+                        }
+                        // also add computed styles for FF
+                        elem.css( key, css );
+                    });
+                    if ( !change ) {
+                        window.setTimeout( function() {
+                            options.complete.call( elem[0] );
+                        }, options.duration );
+                        return;
+                    }
+
+                    // the css strings to be applied
+                    strings = [];
+
+                    // the easing bezier
+                    easing = options.easing in easings ? easings[ options.easing ] : easings._default;
+
+                    // the syntax
+                    syntax = ' ' + options.duration + 'ms' + ' cubic-bezier('  + easing.join(',') + ')';
+
+                    // add a tiny timeout so that the browsers catches any css changes before animating
+                    window.setTimeout( (function(elem, endEvent, to, syntax) {
+                        return function() {
+
+                            // attach the end event
+                            elem.one(endEvent, (function( elem ) {
+                                return function() {
+
+                                    // clear the animation
+                                    clearStyle(elem);
+
+                                    // run the complete method
+                                    options.complete.call(elem[0]);
+                                };
+                            }( elem )));
+
+                            // do the webkit translate3d for better performance on iOS
+                            if( Galleria.WEBKIT && Galleria.TOUCH ) {
+
+                                revert = {};
+                                form = [0,0,0];
+
+                                $.each( ['left', 'top'], function(i, m) {
+                                    if ( m in to ) {
+                                        form[ i ] = ( Utils.parseValue( to[ m ] ) - Utils.parseValue(elem.css( m )) ) + 'px';
+                                        revert[ m ] = to[ m ];
+                                        delete to[ m ];
+                                    }
+                                });
+
+                                if ( form[0] || form[1]) {
+
+                                    elem.data('revert', revert);
+
+                                    strings.push('-webkit-transform' + syntax);
+
+                                    // 3d animate
+                                    setStyle( elem, 'translate3d(' + form.join(',') + ')', 'transform');
+                                }
+                            }
+
+                            // push the animation props
+                            $.each(to, function( p, val ) {
+                                strings.push(p + syntax);
+                            });
+
+                            // set the animation styles
+                            setStyle( elem, strings.join(',') );
+
+                            // animate
+                            elem.css( to );
+
+                        };
+                    }(elem, endEvent, to, syntax)), 2);
+                };
+            }()),
+
+            removeAlpha : function( elem ) {
+                if ( elem instanceof jQuery ) {
+                    elem = elem[0];
+                }
+                if ( IE < 9 && elem ) {
+
+                    var style = elem.style,
+                        currentStyle = elem.currentStyle,
+                        filter = currentStyle && currentStyle.filter || style.filter || "";
+
+                    if ( /alpha/.test( filter ) ) {
+                        style.filter = filter.replace( /alpha\([^)]*\)/i, '' );
+                    }
+                }
+            },
+
+            forceStyles : function( elem, styles ) {
+                elem = $(elem);
+                if ( elem.attr( 'style' ) ) {
+                    elem.data( 'styles', elem.attr( 'style' ) ).removeAttr( 'style' );
+                }
+                elem.css( styles );
+            },
+
+            revertStyles : function() {
+                $.each( Utils.array( arguments ), function( i, elem ) {
+
+                    elem = $( elem );
+                    elem.removeAttr( 'style' );
+
+                    elem.attr('style',''); // "fixes" webkit bug
+
+                    if ( elem.data( 'styles' ) ) {
+                        elem.attr( 'style', elem.data('styles') ).data( 'styles', null );
+                    }
+                });
+            },
+
+            moveOut : function( elem ) {
+                Utils.forceStyles( elem, {
+                    position: 'absolute',
+                    left: -10000
+                });
+            },
+
+            moveIn : function() {
+                Utils.revertStyles.apply( Utils, Utils.array( arguments ) );
+            },
+
+            hide : function( elem, speed, callback ) {
+
+                callback = callback || F;
+
+                var $elem = $(elem);
+                elem = $elem[0];
+
+                // save the value if not exist
+                if (! $elem.data('opacity') ) {
+                    $elem.data('opacity', $elem.css('opacity') );
+                }
+
+                // always hide
+                var style = { opacity: 0 };
+
+                if (speed) {
+
+                    var complete = IE < 9 && elem ? function() {
+                        Utils.removeAlpha( elem );
+                        elem.style.visibility = 'hidden';
+                        callback.call( elem );
+                    } : callback;
+
+                    Utils.animate( elem, style, {
+                        duration: speed,
+                        complete: complete,
+                        stop: true
+                    });
+                } else {
+                    if ( IE < 9 && elem ) {
+                        Utils.removeAlpha( elem );
+                        elem.style.visibility = 'hidden';
+                    } else {
+                        $elem.css( style );
+                    }
+                }
+            },
+
+            show : function( elem, speed, callback ) {
+
+                callback = callback || F;
+
+                var $elem = $(elem);
+                elem = $elem[0];
+
+                // bring back saved opacity
+                var saved = parseFloat( $elem.data('opacity') ) || 1,
+                    style = { opacity: saved };
+
+                // animate or toggle
+                if (speed) {
+
+                    if ( IE < 9 ) {
+                        $elem.css('opacity', 0);
+                        elem.style.visibility = 'visible';
+                    }
+
+                    var complete = IE < 9 && elem ? function() {
+                        if ( style.opacity == 1 ) {
+                            Utils.removeAlpha( elem );
+                        }
+                        callback.call( elem );
+                    } : callback;
+
+                    Utils.animate( elem, style, {
+                        duration: speed,
+                        complete: complete,
+                        stop: true
+                    });
+                } else {
+                    if ( IE < 9 && style.opacity == 1 && elem ) {
+                        Utils.removeAlpha( elem );
+                        elem.style.visibility = 'visible';
+                    } else {
+                        $elem.css( style );
+                    }
+                }
+            },
+
+            wait : function(options) {
+
+                Galleria._waiters = Galleria._waiters || [];
+
+                options = $.extend({
+                    until : FALSE,
+                    success : F,
+                    error : function() { Galleria.raise('Could not complete wait function.'); },
+                    timeout: 3000
+                }, options);
+
+                var start = Utils.timestamp(),
+                    elapsed,
+                    now,
+                    tid,
+                    fn = function() {
+                        now = Utils.timestamp();
+                        elapsed = now - start;
+                        Utils.removeFromArray( Galleria._waiters, tid );
+                        if ( options.until( elapsed ) ) {
+                            options.success();
+                            return false;
+                        }
+                        if (typeof options.timeout == 'number' && now >= start + options.timeout) {
+                            options.error();
+                            return false;
+                        }
+                        Galleria._waiters.push( tid = window.setTimeout(fn, 10) );
+                    };
+                Galleria._waiters.push( tid = window.setTimeout(fn, 10) );
+            },
+
+            toggleQuality : function( img, force ) {
+
+                if ( ( IE !== 7 && IE !== 8 ) || !img || img.nodeName.toUpperCase() != 'IMG' ) {
+                    return;
+                }
+
+                if ( typeof force === 'undefined' ) {
+                    force = img.style.msInterpolationMode === 'nearest-neighbor';
+                }
+
+                img.style.msInterpolationMode = force ? 'bicubic' : 'nearest-neighbor';
+            },
+
+            insertStyleTag : function( styles, id ) {
+
+                if ( id && $( '#'+id ).length ) {
+                    return;
+                }
+
+                var style = doc.createElement( 'style' );
+                if ( id ) {
+                    style.id = id;
+                }
+
+                DOM().head.appendChild( style );
+
+                if ( style.styleSheet ) { // IE
+                    style.styleSheet.cssText = styles;
+                } else {
+                    var cssText = doc.createTextNode( styles );
+                    style.appendChild( cssText );
+                }
+            },
+
+            // a loadscript method that works for local scripts
+            loadScript: function( url, callback ) {
+
+                var done = false,
+                    script = $('<scr'+'ipt>').attr({
+                        src: url,
+                        async: true
+                    }).get(0);
+
+               // Attach handlers for all browsers
+               script.onload = script.onreadystatechange = function() {
+                   if ( !done && (!this.readyState ||
+                       this.readyState === 'loaded' || this.readyState === 'complete') ) {
+
+                       done = true;
+
+                       // Handle memory leak in IE
+                       script.onload = script.onreadystatechange = null;
+
+                       if (typeof callback === 'function') {
+                           callback.call( this, this );
+                       }
+                   }
+               };
+
+               DOM().head.appendChild( script );
+            },
+
+            // parse anything into a number
+            parseValue: function( val ) {
+                if (typeof val === 'number') {
+                    return val;
+                } else if (typeof val === 'string') {
+                    var arr = val.match(/\-?\d|\./g);
+                    return arr && arr.constructor === Array ? arr.join('')*1 : 0;
+                } else {
+                    return 0;
+                }
+            },
+
+            // timestamp abstraction
+            timestamp: function() {
+                return new Date().getTime();
+            },
+
+            loadCSS : function( href, id, callback ) {
+
+                var link,
+                    length;
+
+                // look for manual css
+                $('link[rel=stylesheet]').each(function() {
+                    if ( new RegExp( href ).test( this.href ) ) {
+                        link = this;
+                        return false;
+                    }
+                });
+
+                if ( typeof id === 'function' ) {
+                    callback = id;
+                    id = undef;
+                }
+
+                callback = callback || F; // dirty
+
+                // if already present, return
+                if ( link ) {
+                    callback.call( link, link );
+                    return link;
+                }
+
+                // save the length of stylesheets to check against
+                length = doc.styleSheets.length;
+
+                // check for existing id
+                if( $( '#' + id ).length ) {
+
+                    $( '#' + id ).attr( 'href', href );
+                    length--;
+
+                } else {
+                    link = $( '<link>' ).attr({
+                        rel: 'stylesheet',
+                        href: href,
+                        id: id
+                    }).get(0);
+
+                    var styles = $('link[rel="stylesheet"], style');
+                    if ( styles.length ) {
+                        styles.get(0).parentNode.insertBefore( link, styles[0] );
+                    } else {
+                        DOM().head.appendChild( link );
+                    }
+
+                    if ( IE && length >= 31 ) {
+                        Galleria.raise( 'You have reached the browser stylesheet limit (31)', true );
+                        return;
+                    }
+                }
+
+                if ( typeof callback === 'function' ) {
+
+                    // First check for dummy element (new in 1.2.8)
+                    var $loader = $('<s>').attr( 'id', 'galleria-loader' ).hide().appendTo( DOM().body );
+
+                    Utils.wait({
+                        until: function() {
+                            return $loader.height() == 1;
+                        },
+                        success: function() {
+                            $loader.remove();
+                            callback.call( link, link );
+                        },
+                        error: function() {
+                            $loader.remove();
+
+                            // If failed, tell the dev to download the latest theme
+                            Galleria.raise( 'Theme CSS could not load after 20 sec. ' + ( Galleria.QUIRK ?
+                                'Your browser is in Quirks Mode, please add a correct doctype.' :
+                                'Please download the latest theme at http://galleria.io/customer/.' ), true );
+                        },
+                        timeout: 5000
+                    });
+                }
+                return link;
+            }
+        };
+    }()),
+
+    // play icon
+    _playIcon = function( container ) {
+
+        var css = '.galleria-videoicon{width:60px;height:60px;position:absolute;top:50%;left:50%;z-index:1;' +
+                  'margin:-30px 0 0 -30px;cursor:pointer;background:#000;background:rgba(0,0,0,.8);border-radius:3px;-webkit-transition:all 150ms}' +
+                  '.galleria-videoicon i{width:0px;height:0px;border-style:solid;border-width:10px 0 10px 16px;display:block;' +
+                  'border-color:transparent transparent transparent #ffffff;margin:20px 0 0 22px}.galleria-image:hover .galleria-videoicon{background:#000}';
+
+        Utils.insertStyleTag( css, 'galleria-videoicon' );
+
+        return $( Utils.create( 'galleria-videoicon' ) ).html( '<i></i>' ).appendTo( container )
+            .click( function() { $( this ).siblings( 'img' ).mouseup(); });
+    },
+
+    // the transitions holder
+    _transitions = (function() {
+
+        var _slide = function(params, complete, fade, door) {
+
+            var easing = this.getOptions('easing'),
+                distance = this.getStageWidth(),
+                from = { left: distance * ( params.rewind ? -1 : 1 ) },
+                to = { left: 0 };
+
+            if ( fade ) {
+                from.opacity = 0;
+                to.opacity = 1;
+            } else {
+                from.opacity = 1;
+            }
+
+            $(params.next).css(from);
+
+            Utils.animate(params.next, to, {
+                duration: params.speed,
+                complete: (function( elems ) {
+                    return function() {
+                        complete();
+                        elems.css({
+                            left: 0
+                        });
+                    };
+                }( $( params.next ).add( params.prev ) )),
+                queue: false,
+                easing: easing
+            });
+
+            if (door) {
+                params.rewind = !params.rewind;
+            }
+
+            if (params.prev) {
+
+                from = { left: 0 };
+                to = { left: distance * ( params.rewind ? 1 : -1 ) };
+
+                if ( fade ) {
+                    from.opacity = 1;
+                    to.opacity = 0;
+                }
+
+                $(params.prev).css(from);
+                Utils.animate(params.prev, to, {
+                    duration: params.speed,
+                    queue: false,
+                    easing: easing,
+                    complete: function() {
+                        $(this).css('opacity', 0);
+                    }
+                });
+            }
+        };
+
+        return {
+
+            active: false,
+
+            init: function( effect, params, complete ) {
+                if ( _transitions.effects.hasOwnProperty( effect ) ) {
+                    _transitions.effects[ effect ].call( this, params, complete );
+                }
+            },
+
+            effects: {
+
+                fade: function(params, complete) {
+                    $(params.next).css({
+                        opacity: 0,
+                        left: 0
+                    });
+                    Utils.animate(params.next, {
+                        opacity: 1
+                    },{
+                        duration: params.speed,
+                        complete: complete
+                    });
+                    if (params.prev) {
+                        $(params.prev).css('opacity',1).show();
+                        Utils.animate(params.prev, {
+                            opacity: 0
+                        },{
+                            duration: params.speed
+                        });
+                    }
+                },
+
+                flash: function(params, complete) {
+                    $(params.next).css({
+                        opacity: 0,
+                        left: 0
+                    });
+                    if (params.prev) {
+                        Utils.animate( params.prev, {
+                            opacity: 0
+                        },{
+                            duration: params.speed/2,
+                            complete: function() {
+                                Utils.animate( params.next, {
+                                    opacity:1
+                                },{
+                                    duration: params.speed,
+                                    complete: complete
+                                });
+                            }
+                        });
+                    } else {
+                        Utils.animate( params.next, {
+                            opacity: 1
+                        },{
+                            duration: params.speed,
+                            complete: complete
+                        });
+                    }
+                },
+
+                pulse: function(params, complete) {
+                    if (params.prev) {
+                        $(params.prev).hide();
+                    }
+                    $(params.next).css({
+                        opacity: 0,
+                        left: 0
+                    }).show();
+                    Utils.animate(params.next, {
+                        opacity:1
+                    },{
+                        duration: params.speed,
+                        complete: complete
+                    });
+                },
+
+                slide: function(params, complete) {
+                    _slide.apply( this, Utils.array( arguments ) );
+                },
+
+                fadeslide: function(params, complete) {
+                    _slide.apply( this, Utils.array( arguments ).concat( [true] ) );
+                },
+
+                doorslide: function(params, complete) {
+                    _slide.apply( this, Utils.array( arguments ).concat( [false, true] ) );
+                }
+            }
+        };
+    }());
+
+// listen to fullscreen
+_nativeFullscreen.listen();
+
+// trigger resize on orientationchange (IOS7)
+$win.bind( 'orientationchange', function() {
+    $(this).resize();
+});
+
+/**
+    The main Galleria class
+
+    @class
+    @constructor
+
+    @example var gallery = new Galleria();
+
+    @author http://aino.se
+
+    @requires jQuery
+
+*/
+
+Galleria = window.Galleria = function() {
+
+    var self = this;
+
+    // internal options
+    this._options = {};
+
+    // flag for controlling play/pause
+    this._playing = false;
+
+    // internal interval for slideshow
+    this._playtime = 5000;
+
+    // internal variable for the currently active image
+    this._active = null;
+
+    // the internal queue, arrayified
+    this._queue = { length: 0 };
+
+    // the internal data array
+    this._data = [];
+
+    // the internal dom collection
+    this._dom = {};
+
+    // the internal thumbnails array
+    this._thumbnails = [];
+
+    // the internal layers array
+    this._layers = [];
+
+    // internal init flag
+    this._initialized = false;
+
+    // internal firstrun flag
+    this._firstrun = false;
+
+    // global stagewidth/height
+    this._stageWidth = 0;
+    this._stageHeight = 0;
+
+    // target holder
+    this._target = undef;
+
+    // bind hashes
+    this._binds = [];
+
+    // instance id
+    this._id = parseInt(M.random()*10000, 10);
+
+    // add some elements
+    var divs =  'container stage images image-nav image-nav-left image-nav-right ' +
+                'info info-text info-title info-description ' +
+                'thumbnails thumbnails-list thumbnails-container thumb-nav-left thumb-nav-right ' +
+                'loader counter tooltip',
+        spans = 'current total';
+
+    $.each( divs.split(' '), function( i, elemId ) {
+        self._dom[ elemId ] = Utils.create( 'galleria-' + elemId );
+    });
+
+    $.each( spans.split(' '), function( i, elemId ) {
+        self._dom[ elemId ] = Utils.create( 'galleria-' + elemId, 'span' );
+    });
+
+    // the internal keyboard object
+    // keeps reference of the keybinds and provides helper methods for binding keys
+    var keyboard = this._keyboard = {
+
+        keys : {
+            'UP': 38,
+            'DOWN': 40,
+            'LEFT': 37,
+            'RIGHT': 39,
+            'RETURN': 13,
+            'ESCAPE': 27,
+            'BACKSPACE': 8,
+            'SPACE': 32
+        },
+
+        map : {},
+
+        bound: false,
+
+        press: function(e) {
+            var key = e.keyCode || e.which;
+            if ( key in keyboard.map && typeof keyboard.map[key] === 'function' ) {
+                keyboard.map[key].call(self, e);
+            }
+        },
+
+        attach: function(map) {
+
+            var key, up;
+
+            for( key in map ) {
+                if ( map.hasOwnProperty( key ) ) {
+                    up = key.toUpperCase();
+                    if ( up in keyboard.keys ) {
+                        keyboard.map[ keyboard.keys[up] ] = map[key];
+                    } else {
+                        keyboard.map[ up ] = map[key];
+                    }
+                }
+            }
+            if ( !keyboard.bound ) {
+                keyboard.bound = true;
+                $doc.bind('keydown', keyboard.press);
+            }
+        },
+
+        detach: function() {
+            keyboard.bound = false;
+            keyboard.map = {};
+            $doc.unbind('keydown', keyboard.press);
+        }
+    };
+
+    // internal controls for keeping track of active / inactive images
+    var controls = this._controls = {
+
+        0: undef,
+
+        1: undef,
+
+        active : 0,
+
+        swap : function() {
+            controls.active = controls.active ? 0 : 1;
+        },
+
+        getActive : function() {
+            return self._options.swipe ? controls.slides[ self._active ] : controls[ controls.active ];
+        },
+
+        getNext : function() {
+            return self._options.swipe ? controls.slides[ self.getNext( self._active ) ] : controls[ 1 - controls.active ];
+        },
+
+        slides : [],
+
+        frames: [],
+
+        layers: []
+    };
+
+    // internal carousel object
+    var carousel = this._carousel = {
+
+        // shortcuts
+        next: self.$('thumb-nav-right'),
+        prev: self.$('thumb-nav-left'),
+
+        // cache the width
+        width: 0,
+
+        // track the current position
+        current: 0,
+
+        // cache max value
+        max: 0,
+
+        // save all hooks for each width in an array
+        hooks: [],
+
+        // update the carousel
+        // you can run this method anytime, f.ex on window.resize
+        update: function() {
+            var w = 0,
+                h = 0,
+                hooks = [0];
+
+            $.each( self._thumbnails, function( i, thumb ) {
+                if ( thumb.ready ) {
+                    w += thumb.outerWidth || $( thumb.container ).outerWidth( true );
+                    // Due to a bug in jquery, outerwidth() returns the floor of the actual outerwidth,
+                    // if the browser is zoom to a value other than 100%. height() returns the floating point value.
+                    var containerWidth = $( thumb.container).width();
+                    w += containerWidth - M.floor(containerWidth);
+
+                    hooks[ i+1 ] = w;
+                    h = M.max( h, thumb.outerHeight || $( thumb.container).outerHeight( true ) );
+                }
+            });
+
+            self.$( 'thumbnails' ).css({
+                width: w,
+                height: h
+            });
+
+            carousel.max = w;
+            carousel.hooks = hooks;
+            carousel.width = self.$( 'thumbnails-list' ).width();
+            carousel.setClasses();
+
+            self.$( 'thumbnails-container' ).toggleClass( 'galleria-carousel', w > carousel.width );
+
+            // one extra calculation
+            carousel.width = self.$( 'thumbnails-list' ).width();
+
+            // todo: fix so the carousel moves to the left
+        },
+
+        bindControls: function() {
+
+            var i;
+
+            carousel.next.bind( 'click', function(e) {
+                e.preventDefault();
+
+                if ( self._options.carouselSteps === 'auto' ) {
+
+                    for ( i = carousel.current; i < carousel.hooks.length; i++ ) {
+                        if ( carousel.hooks[i] - carousel.hooks[ carousel.current ] > carousel.width ) {
+                            carousel.set(i - 2);
+                            break;
+                        }
+                    }
+
+                } else {
+                    carousel.set( carousel.current + self._options.carouselSteps);
+                }
+            });
+
+            carousel.prev.bind( 'click', function(e) {
+                e.preventDefault();
+
+                if ( self._options.carouselSteps === 'auto' ) {
+
+                    for ( i = carousel.current; i >= 0; i-- ) {
+                        if ( carousel.hooks[ carousel.current ] - carousel.hooks[i] > carousel.width ) {
+                            carousel.set( i + 2 );
+                            break;
+                        } else if ( i === 0 ) {
+                            carousel.set( 0 );
+                            break;
+                        }
+                    }
+                } else {
+                    carousel.set( carousel.current - self._options.carouselSteps );
+                }
+            });
+        },
+
+        // calculate and set positions
+        set: function( i ) {
+            i = M.max( i, 0 );
+            while ( carousel.hooks[i - 1] + carousel.width >= carousel.max && i >= 0 ) {
+                i--;
+            }
+            carousel.current = i;
+            carousel.animate();
+        },
+
+        // get the last position
+        getLast: function(i) {
+            return ( i || carousel.current ) - 1;
+        },
+
+        // follow the active image
+        follow: function(i) {
+
+            //don't follow if position fits
+            if ( i === 0 || i === carousel.hooks.length - 2 ) {
+                carousel.set( i );
+                return;
+            }
+
+            // calculate last position
+            var last = carousel.current;
+            while( carousel.hooks[last] - carousel.hooks[ carousel.current ] <
+                   carousel.width && last <= carousel.hooks.length ) {
+                last ++;
+            }
+
+            // set position
+            if ( i - 1 < carousel.current ) {
+                carousel.set( i - 1 );
+            } else if ( i + 2 > last) {
+                carousel.set( i - last + carousel.current + 2 );
+            }
+        },
+
+        // helper for setting disabled classes
+        setClasses: function() {
+            carousel.prev.toggleClass( 'disabled', !carousel.current );
+            carousel.next.toggleClass( 'disabled', carousel.hooks[ carousel.current ] + carousel.width >= carousel.max );
+        },
+
+        // the animation method
+        animate: function(to) {
+            carousel.setClasses();
+            var num = carousel.hooks[ carousel.current ] * -1;
+
+            if ( isNaN( num ) ) {
+                return;
+            }
+
+            // FF 24 bug
+            self.$( 'thumbnails' ).css('left', function() {
+                return $(this).css('left');
+            });
+
+            Utils.animate(self.get( 'thumbnails' ), {
+                left: num
+            },{
+                duration: self._options.carouselSpeed,
+                easing: self._options.easing,
+                queue: false
+            });
+        }
+    };
+
+    // tooltip control
+    // added in 1.2
+    var tooltip = this._tooltip = {
+
+        initialized : false,
+
+        open: false,
+
+        timer: 'tooltip' + self._id,
+
+        swapTimer: 'swap' + self._id,
+
+        init: function() {
+
+            tooltip.initialized = true;
+
+            var css = '.galleria-tooltip{padding:3px 8px;max-width:50%;background:#ffe;color:#000;z-index:3;position:absolute;font-size:11px;line-height:1.3;' +
+                      'opacity:0;box-shadow:0 0 2px rgba(0,0,0,.4);-moz-box-shadow:0 0 2px rgba(0,0,0,.4);-webkit-box-shadow:0 0 2px rgba(0,0,0,.4);}';
+
+            Utils.insertStyleTag( css, 'galleria-tooltip' );
+
+            self.$( 'tooltip' ).css({
+                opacity: 0.8,
+                visibility: 'visible',
+                display: 'none'
+            });
+
+        },
+
+        // move handler
+        move: function( e ) {
+            var mouseX = self.getMousePosition(e).x,
+                mouseY = self.getMousePosition(e).y,
+                $elem = self.$( 'tooltip' ),
+                x = mouseX,
+                y = mouseY,
+                height = $elem.outerHeight( true ) + 1,
+                width = $elem.outerWidth( true ),
+                limitY = height + 15;
+
+            var maxX = self.$( 'container' ).width() - width - 2,
+                maxY = self.$( 'container' ).height() - height - 2;
+
+            if ( !isNaN(x) && !isNaN(y) ) {
+
+                x += 10;
+                y -= ( height+8 );
+
+                x = M.max( 0, M.min( maxX, x ) );
+                y = M.max( 0, M.min( maxY, y ) );
+
+                if( mouseY < limitY ) {
+                    y = limitY;
+                }
+
+                $elem.css({ left: x, top: y });
+            }
+        },
+
+        // bind elements to the tooltip
+        // you can bind multiple elementIDs using { elemID : function } or { elemID : string }
+        // you can also bind single DOM elements using bind(elem, string)
+        bind: function( elem, value ) {
+
+            // todo: revise if alternative tooltip is needed for mobile devices
+            if (Galleria.TOUCH) {
+                return;
+            }
+
+            if (! tooltip.initialized ) {
+                tooltip.init();
+            }
+
+            var mouseout = function() {
+                self.$( 'container' ).unbind( 'mousemove', tooltip.move );
+                self.clearTimer( tooltip.timer );
+
+                self.$( 'tooltip' ).stop().animate({
+                    opacity: 0
+                }, 200, function() {
+
+                    self.$( 'tooltip' ).hide();
+
+                    self.addTimer( tooltip.swapTimer, function() {
+                        tooltip.open = false;
+                    }, 1000);
+                });
+            };
+
+            var hover = function( elem, value) {
+
+                tooltip.define( elem, value );
+
+                $( elem ).hover(function() {
+
+                    self.clearTimer( tooltip.swapTimer );
+                    self.$('container').unbind( 'mousemove', tooltip.move ).bind( 'mousemove', tooltip.move ).trigger( 'mousemove' );
+                    tooltip.show( elem );
+
+                    self.addTimer( tooltip.timer, function() {
+                        self.$( 'tooltip' ).stop().show().animate({
+                            opacity: 1
+                        });
+                        tooltip.open = true;
+
+                    }, tooltip.open ? 0 : 500);
+
+                }, mouseout).click(mouseout);
+            };
+
+            if ( typeof value === 'string' ) {
+                hover( ( elem in self._dom ? self.get( elem ) : elem ), value );
+            } else {
+                // asume elemID here
+                $.each( elem, function( elemID, val ) {
+                    hover( self.get(elemID), val );
+                });
+            }
+        },
+
+        show: function( elem ) {
+
+            elem = $( elem in self._dom ? self.get(elem) : elem );
+
+            var text = elem.data( 'tt' ),
+                mouseup = function( e ) {
+
+                    // attach a tiny settimeout to make sure the new tooltip is filled
+                    window.setTimeout( (function( ev ) {
+                        return function() {
+                            tooltip.move( ev );
+                        };
+                    }( e )), 10);
+
+                    elem.unbind( 'mouseup', mouseup );
+
+                };
+
+            text = typeof text === 'function' ? text() : text;
+
+            if ( ! text ) {
+                return;
+            }
+
+            self.$( 'tooltip' ).html( text.replace(/\s/, ' ') );
+
+            // trigger mousemove on mouseup in case of click
+            elem.bind( 'mouseup', mouseup );
+        },
+
+        define: function( elem, value ) {
+
+            // we store functions, not strings
+            if (typeof value !== 'function') {
+                var s = value;
+                value = function() {
+                    return s;
+                };
+            }
+
+            elem = $( elem in self._dom ? self.get(elem) : elem ).data('tt', value);
+
+            tooltip.show( elem );
+
+        }
+    };
+
+    // internal fullscreen control
+    var fullscreen = this._fullscreen = {
+
+        scrolled: 0,
+
+        crop: undef,
+
+        active: false,
+
+        prev: $(),
+
+        beforeEnter: function(fn){ fn(); },
+        beforeExit:  function(fn){ fn(); },
+
+        keymap: self._keyboard.map,
+
+        parseCallback: function( callback, enter ) {
+
+            return _transitions.active ? function() {
+                if ( typeof callback == 'function' ) {
+                    callback.call(self);
+                }
+                var active = self._controls.getActive(),
+                    next = self._controls.getNext();
+
+                self._scaleImage( next );
+                self._scaleImage( active );
+
+                if ( enter && self._options.trueFullscreen ) {
+                    // Firefox bug, revise later
+                    $( active.container ).add( next.container ).trigger( 'transitionend' );
+                }
+
+            } : callback;
+
+        },
+
+        enter: function( callback ) {
+
+            fullscreen.beforeEnter(function() {
+
+                callback = fullscreen.parseCallback( callback, true );
+
+                if ( self._options.trueFullscreen && _nativeFullscreen.support ) {
+
+                    // do some stuff prior animation for wmoother transitions
+
+                    fullscreen.active = true;
+
+                    Utils.forceStyles( self.get('container'), {
+                        width: '100%',
+                        height: '100%'
+                    });
+
+                    self.rescale();
+
+                    if ( Galleria.MAC ) {
+                        if ( !( Galleria.SAFARI && /version\/[1-5]/.test(NAV)) ) {
+                            self.$('container').css('opacity', 0).addClass('fullscreen');
+                            window.setTimeout(function() {
+                                fullscreen.scale();
+                                self.$('container').css('opacity', 1);
+                            }, 50);
+                        } else {
+                            self.$('stage').css('opacity', 0);
+                            window.setTimeout(function() {
+                                fullscreen.scale();
+                                self.$('stage').css('opacity', 1);
+                            },4);
+                        }
+                    } else {
+                        self.$('container').addClass('fullscreen');
+                    }
+
+                    $win.resize( fullscreen.scale );
+
+                    _nativeFullscreen.enter( self, callback, self.get('container') );
+
+                } else {
+
+                    fullscreen.scrolled = $win.scrollTop();
+                    if( !Galleria.TOUCH ) {
+                        window.scrollTo(0, 0);
+                    }
+
+                    fullscreen._enter( callback );
+                }
+            });
+
+        },
+
+        _enter: function( callback ) {
+
+            fullscreen.active = true;
+
+            if ( IFRAME ) {
+
+                fullscreen.iframe = (function() {
+
+                    var elem,
+                        refer = doc.referrer,
+                        test = doc.createElement('a'),
+                        loc = window.location;
+
+                    test.href = refer;
+
+                    if( test.protocol != loc.protocol ||
+                        test.hostname != loc.hostname ||
+                        test.port != loc.port ) {
+                            Galleria.raise('Parent fullscreen not available. Iframe protocol, domains and ports must match.');
+                            return false;
+                        }
+
+                    fullscreen.pd = window.parent.document;
+
+                    $( fullscreen.pd ).find('iframe').each(function() {
+                        var idoc = this.contentDocument || this.contentWindow.document;
+                        if ( idoc === doc ) {
+                            elem = this;
+                            return false;
+                        }
+                    });
+
+                    return elem;
+                }());
+
+            }
+
+            // hide the image until rescale is complete
+            Utils.hide( self.getActiveImage() );
+
+            if ( IFRAME && fullscreen.iframe ) {
+                fullscreen.iframe.scrolled = $( window.parent ).scrollTop();
+                window.parent.scrollTo(0, 0);
+            }
+
+            var data = self.getData(),
+                options = self._options,
+                inBrowser = !self._options.trueFullscreen || !_nativeFullscreen.support,
+                htmlbody = {
+                    height: '100%',
+                    overflow: 'hidden',
+                    margin:0,
+                    padding:0
+                };
+
+            if (inBrowser) {
+
+                self.$('container').addClass('fullscreen');
+                fullscreen.prev = self.$('container').prev();
+
+                if ( !fullscreen.prev.length ) {
+                    fullscreen.parent = self.$( 'container' ).parent();
+                }
+
+                // move
+                self.$( 'container' ).appendTo( 'body' );
+
+                // begin styleforce
+
+                Utils.forceStyles(self.get('container'), {
+                    position: Galleria.TOUCH ? 'absolute' : 'fixed',
+                    top: 0,
+                    left: 0,
+                    width: '100%',
+                    height: '100%',
+                    zIndex: 10000
+                });
+                Utils.forceStyles( DOM().html, htmlbody );
+                Utils.forceStyles( DOM().body, htmlbody );
+            }
+
+            if ( IFRAME && fullscreen.iframe ) {
+                Utils.forceStyles( fullscreen.pd.documentElement, htmlbody );
+                Utils.forceStyles( fullscreen.pd.body, htmlbody );
+                Utils.forceStyles( fullscreen.iframe, $.extend( htmlbody, {
+                    width: '100%',
+                    height: '100%',
+                    top: 0,
+                    left: 0,
+                    position: 'fixed',
+                    zIndex: 10000,
+                    border: 'none'
+                }));
+            }
+
+            // temporarily attach some keys
+            // save the old ones first in a cloned object
+            fullscreen.keymap = $.extend({}, self._keyboard.map);
+
+            self.attachKeyboard({
+                escape: self.exitFullscreen,
+                right: self.next,
+                left: self.prev
+            });
+
+            // temporarily save the crop
+            fullscreen.crop = options.imageCrop;
+
+            // set fullscreen options
+            if ( options.fullscreenCrop != undef ) {
+                options.imageCrop = options.fullscreenCrop;
+            }
+
+            // swap to big image if it's different from the display image
+            if ( data && data.big && data.image !== data.big ) {
+                var big    = new Galleria.Picture(),
+                    cached = big.isCached( data.big ),
+                    index  = self.getIndex(),
+                    thumb  = self._thumbnails[ index ];
+
+                self.trigger( {
+                    type: Galleria.LOADSTART,
+                    cached: cached,
+                    rewind: false,
+                    index: index,
+                    imageTarget: self.getActiveImage(),
+                    thumbTarget: thumb,
+                    galleriaData: data
+                });
+
+                big.load( data.big, function( big ) {
+                    self._scaleImage( big, {
+                        complete: function( big ) {
+                            self.trigger({
+                                type: Galleria.LOADFINISH,
+                                cached: cached,
+                                index: index,
+                                rewind: false,
+                                imageTarget: big.image,
+                                thumbTarget: thumb
+                            });
+                            var image = self._controls.getActive().image;
+                            if ( image ) {
+                                $( image ).width( big.image.width ).height( big.image.height )
+                                    .attr( 'style', $( big.image ).attr('style') )
+                                    .attr( 'src', big.image.src );
+                            }
+                        }
+                    });
+                });
+            }
+
+            // init the first rescale and attach callbacks
+
+            self.rescale(function() {
+
+                self.addTimer(false, function() {
+                    // show the image after 50 ms
+                    if ( inBrowser ) {
+                        Utils.show( self.getActiveImage() );
+                    }
+
+                    if (typeof callback === 'function') {
+                        callback.call( self );
+                    }
+                    self.rescale();
+
+                }, 100);
+
+                self.trigger( Galleria.FULLSCREEN_ENTER );
+            });
+
+            if ( !inBrowser ) {
+                Utils.show( self.getActiveImage() );
+            } else {
+                $win.resize( fullscreen.scale );
+            }
+
+        },
+
+        scale : function() {
+            self.rescale();
+        },
+
+        exit: function( callback ) {
+
+            fullscreen.beforeExit(function() {
+
+                callback = fullscreen.parseCallback( callback );
+
+                if ( self._options.trueFullscreen && _nativeFullscreen.support ) {
+                    _nativeFullscreen.exit( callback );
+                } else {
+                    fullscreen._exit( callback );
+                }
+            });
+        },
+
+        _exit: function( callback ) {
+
+            fullscreen.active = false;
+
+            var inBrowser = !self._options.trueFullscreen || !_nativeFullscreen.support,
+                $container = self.$( 'container' ).removeClass( 'fullscreen' );
+
+            // move back
+            if ( fullscreen.parent ) {
+                fullscreen.parent.prepend( $container );
+            } else {
+                $container.insertAfter( fullscreen.prev );
+            }
+
+            if ( inBrowser ) {
+                Utils.hide( self.getActiveImage() );
+
+                // revert all styles
+                Utils.revertStyles( self.get('container'), DOM().html, DOM().body );
+
+                // scroll back
+                if( !Galleria.TOUCH ) {
+                    window.scrollTo(0, fullscreen.scrolled);
+                }
+
+                // reload iframe src manually
+                var frame = self._controls.frames[ self._controls.active ];
+                if ( frame && frame.image ) {
+                    frame.image.src = frame.image.src;
+                }
+            }
+
+            if ( IFRAME && fullscreen.iframe ) {
+                Utils.revertStyles( fullscreen.pd.documentElement, fullscreen.pd.body, fullscreen.iframe );
+                if ( fullscreen.iframe.scrolled ) {
+                    window.parent.scrollTo(0, fullscreen.iframe.scrolled );
+                }
+            }
+
+            // detach all keyboard events and apply the old keymap
+            self.detachKeyboard();
+            self.attachKeyboard( fullscreen.keymap );
+
+            // bring back cached options
+            self._options.imageCrop = fullscreen.crop;
+
+            // return to original image
+            var big = self.getData().big,
+                image = self._controls.getActive().image;
+
+            if ( !self.getData().iframe && image && big && big == image.src ) {
+
+                window.setTimeout(function(src) {
+                    return function() {
+                        image.src = src;
+                    };
+                }( self.getData().image ), 1 );
+
+            }
+
+            self.rescale(function() {
+                self.addTimer(false, function() {
+
+                    // show the image after 50 ms
+                    if ( inBrowser ) {
+                        Utils.show( self.getActiveImage() );
+                    }
+
+                    if ( typeof callback === 'function' ) {
+                        callback.call( self );
+                    }
+
+                    $win.trigger( 'resize' );
+
+                }, 50);
+                self.trigger( Galleria.FULLSCREEN_EXIT );
+            });
+
+            $win.unbind('resize', fullscreen.scale);
+        }
+    };
+
+    // the internal idle object for controlling idle states
+    var idle = this._idle = {
+
+        trunk: [],
+
+        bound: false,
+
+        active: false,
+
+        add: function(elem, to, from, hide) {
+            if (!elem) {
+                return;
+            }
+            if (!idle.bound) {
+                idle.addEvent();
+            }
+            elem = $(elem);
+
+            if ( typeof from == 'boolean' ) {
+                hide = from;
+                from = {};
+            }
+
+            from = from || {};
+
+            var extract = {},
+                style;
+
+            for ( style in to ) {
+                if ( to.hasOwnProperty( style ) ) {
+                    extract[ style ] = elem.css( style );
+                }
+            }
+
+            elem.data('idle', {
+                from: $.extend( extract, from ),
+                to: to,
+                complete: true,
+                busy: false
+            });
+
+            if ( !hide ) {
+                idle.addTimer();
+            } else {
+                elem.css( to );
+            }
+            idle.trunk.push(elem);
+        },
+
+        remove: function(elem) {
+
+            elem = $(elem);
+
+            $.each(idle.trunk, function(i, el) {
+                if ( el && el.length && !el.not(elem).length ) {
+                    elem.css( elem.data( 'idle' ).from );
+                    idle.trunk.splice(i, 1);
+                }
+            });
+
+            if (!idle.trunk.length) {
+                idle.removeEvent();
+                self.clearTimer( idle.timer );
+            }
+        },
+
+        addEvent : function() {
+            idle.bound = true;
+            self.$('container').bind( 'mousemove click', idle.showAll );
+            if ( self._options.idleMode == 'hover' ) {
+                self.$('container').bind( 'mouseleave', idle.hide );
+            }
+        },
+
+        removeEvent : function() {
+            idle.bound = false;
+            self.$('container').bind( 'mousemove click', idle.showAll );
+            if ( self._options.idleMode == 'hover' ) {
+                self.$('container').unbind( 'mouseleave', idle.hide );
+            }
+        },
+
+        addTimer : function() {
+            if( self._options.idleMode == 'hover' ) {
+                return;
+            }
+            self.addTimer( 'idle', function() {
+                idle.hide();
+            }, self._options.idleTime );
+        },
+
+        hide : function() {
+
+            if ( !self._options.idleMode || self.getIndex() === false ) {
+                return;
+            }
+
+            self.trigger( Galleria.IDLE_ENTER );
+
+            var len = idle.trunk.length;
+
+            $.each( idle.trunk, function(i, elem) {
+
+                var data = elem.data('idle');
+
+                if (! data) {
+                    return;
+                }
+
+                elem.data('idle').complete = false;
+
+                Utils.animate( elem, data.to, {
+                    duration: self._options.idleSpeed,
+                    complete: function() {
+                        if ( i == len-1 ) {
+                            idle.active = false;
+                        }
+                    }
+                });
+            });
+        },
+
+        showAll : function() {
+
+            self.clearTimer( 'idle' );
+
+            $.each( idle.trunk, function( i, elem ) {
+                idle.show( elem );
+            });
+        },
+
+        show: function(elem) {
+
+            var data = elem.data('idle');
+
+            if ( !idle.active || ( !data.busy && !data.complete ) ) {
+
+                data.busy = true;
+
+                self.trigger( Galleria.IDLE_EXIT );
+
+                self.clearTimer( 'idle' );
+
+                Utils.animate( elem, data.from, {
+                    duration: self._options.idleSpeed/2,
+                    complete: function() {
+                        idle.active = true;
+                        $(elem).data('idle').busy = false;
+                        $(elem).data('idle').complete = true;
+                    }
+                });
+
+            }
+            idle.addTimer();
+        }
+    };
+
+    // internal lightbox object
+    // creates a predesigned lightbox for simple popups of images in galleria
+    var lightbox = this._lightbox = {
+
+        width : 0,
+
+        height : 0,
+
+        initialized : false,
+
+        active : null,
+
+        image : null,
+
+        elems : {},
+
+        keymap: false,
+
+        init : function() {
+
+            if ( lightbox.initialized ) {
+                return;
+            }
+            lightbox.initialized = true;
+
+            // create some elements to work with
+            var elems = 'overlay box content shadow title info close prevholder prev nextholder next counter image',
+                el = {},
+                op = self._options,
+                css = '',
+                abs = 'position:absolute;',
+                prefix = 'lightbox-',
+                cssMap = {
+                    overlay:    'position:fixed;display:none;opacity:'+op.overlayOpacity+';filter:alpha(opacity='+(op.overlayOpacity*100)+
+                                ');top:0;left:0;width:100%;height:100%;background:'+op.overlayBackground+';z-index:99990',
+                    box:        'position:fixed;display:none;width:400px;height:400px;top:50%;left:50%;margin-top:-200px;margin-left:-200px;z-index:99991',
+                    shadow:     abs+'background:#000;width:100%;height:100%;',
+                    content:    abs+'background-color:#fff;top:10px;left:10px;right:10px;bottom:10px;overflow:hidden',
+                    info:       abs+'bottom:10px;left:10px;right:10px;color:#444;font:11px/13px arial,sans-serif;height:13px',
+                    close:      abs+'top:10px;right:10px;height:20px;width:20px;background:#fff;text-align:center;cursor:pointer;color:#444;font:16px/22px arial,sans-serif;z-index:99999',
+                    image:      abs+'top:10px;left:10px;right:10px;bottom:30px;overflow:hidden;display:block;',
+                    prevholder: abs+'width:50%;top:0;bottom:40px;cursor:pointer;',
+                    nextholder: abs+'width:50%;top:0;bottom:40px;right:-1px;cursor:pointer;',
+                    prev:       abs+'top:50%;margin-top:-20px;height:40px;width:30px;background:#fff;left:20px;display:none;text-align:center;color:#000;font:bold 16px/36px arial,sans-serif',
+                    next:       abs+'top:50%;margin-top:-20px;height:40px;width:30px;background:#fff;right:20px;left:auto;display:none;font:bold 16px/36px arial,sans-serif;text-align:center;color:#000',
+                    title:      'float:left',
+                    counter:    'float:right;margin-left:8px;'
+                },
+                hover = function(elem) {
+                    return elem.hover(
+                        function() { $(this).css( 'color', '#bbb' ); },
+                        function() { $(this).css( 'color', '#444' ); }
+                    );
+                },
+                appends = {};
+
+            // IE8 fix for IE's transparent background event "feature"
+            if ( IE && IE > 7 ) {
+                cssMap.nextholder += 'background:#000;filter:alpha(opacity=0);';
+                cssMap.prevholder += 'background:#000;filter:alpha(opacity=0);';
+            }
+
+            // create and insert CSS
+            $.each(cssMap, function( key, value ) {
+                css += '.galleria-'+prefix+key+'{'+value+'}';
+            });
+
+            css += '.galleria-'+prefix+'box.iframe .galleria-'+prefix+'prevholder,'+
+                   '.galleria-'+prefix+'box.iframe .galleria-'+prefix+'nextholder{'+
+                   'width:100px;height:100px;top:50%;margin-top:-70px}';
+
+            Utils.insertStyleTag( css, 'galleria-lightbox' );
+
+            // create the elements
+            $.each(elems.split(' '), function( i, elemId ) {
+                self.addElement( 'lightbox-' + elemId );
+                el[ elemId ] = lightbox.elems[ elemId ] = self.get( 'lightbox-' + elemId );
+            });
+
+            // initiate the image
+            lightbox.image = new Galleria.Picture();
+
+            // append the elements
+            $.each({
+                    box: 'shadow content close prevholder nextholder',
+                    info: 'title counter',
+                    content: 'info image',
+                    prevholder: 'prev',
+                    nextholder: 'next'
+                }, function( key, val ) {
+                    var arr = [];
+                    $.each( val.split(' '), function( i, prop ) {
+                        arr.push( prefix + prop );
+                    });
+                    appends[ prefix+key ] = arr;
+            });
+
+            self.append( appends );
+
+            $( el.image ).append( lightbox.image.container );
+
+            $( DOM().body ).append( el.overlay, el.box );
+
+            // add the prev/next nav and bind some controls
+
+            hover( $( el.close ).bind( 'click', lightbox.hide ).html('×') );
+
+            $.each( ['Prev','Next'], function(i, dir) {
+
+                var $d = $( el[ dir.toLowerCase() ] ).html( /v/.test( dir ) ? '‹ ' : ' ›' ),
+                    $e = $( el[ dir.toLowerCase()+'holder'] );
+
+                $e.bind( 'click', function() {
+                    lightbox[ 'show' + dir ]();
+                });
+
+                // IE7 and touch devices will simply show the nav
+                if ( IE < 8 || Galleria.TOUCH ) {
+                    $d.show();
+                    return;
+                }
+
+                $e.hover( function() {
+                    $d.show();
+                }, function(e) {
+                    $d.stop().fadeOut( 200 );
+                });
+
+            });
+            $( el.overlay ).bind( 'click', lightbox.hide );
+
+            // the lightbox animation is slow on ipad
+            if ( Galleria.IPAD ) {
+                self._options.lightboxTransitionSpeed = 0;
+            }
+
+        },
+
+        rescale: function(event) {
+
+            // calculate
+             var width = M.min( $win.width()-40, lightbox.width ),
+                height = M.min( $win.height()-10, lightbox.height ),
+                ratio = M.min( width / lightbox.width, height / lightbox.height ),
+                destWidth = M.round( lightbox.width * ratio ) + 40,
+                destHeight = M.round( lightbox.height * ratio ) + 10,
+                to = {
+                    width: destWidth,
+                    height: destHeight,
+                    'margin-top': M.ceil( destHeight / 2 ) *- 1,
+                    'margin-left': M.ceil( destWidth / 2 ) *- 1
+                };
+
+            // if rescale event, don't animate
+            if ( event ) {
+                $( lightbox.elems.box ).css( to );
+            } else {
+                $( lightbox.elems.box ).animate( to, {
+                    duration: self._options.lightboxTransitionSpeed,
+                    easing: self._options.easing,
+                    complete: function() {
+                        var image = lightbox.image,
+                            speed = self._options.lightboxFadeSpeed;
+
+                        self.trigger({
+                            type: Galleria.LIGHTBOX_IMAGE,
+                            imageTarget: image.image
+                        });
+
+                        $( image.container ).show();
+
+                        $( image.image ).animate({ opacity: 1 }, speed);
+                        Utils.show( lightbox.elems.info, speed );
+                    }
+                });
+            }
+        },
+
+        hide: function() {
+
+            // remove the image
+            lightbox.image.image = null;
+
+            $win.unbind('resize', lightbox.rescale);
+
+            $( lightbox.elems.box ).hide().find( 'iframe' ).remove();
+
+            Utils.hide( lightbox.elems.info );
+
+            self.detachKeyboard();
+            self.attachKeyboard( lightbox.keymap );
+
+            lightbox.keymap = false;
+
+            Utils.hide( lightbox.elems.overlay, 200, function() {
+                $( this ).hide().css( 'opacity', self._options.overlayOpacity );
+                self.trigger( Galleria.LIGHTBOX_CLOSE );
+            });
+        },
+
+        showNext: function() {
+            lightbox.show( self.getNext( lightbox.active ) );
+        },
+
+        showPrev: function() {
+            lightbox.show( self.getPrev( lightbox.active ) );
+        },
+
+        show: function(index) {
+
+            lightbox.active = index = typeof index === 'number' ? index : self.getIndex() || 0;
+
+            if ( !lightbox.initialized ) {
+                lightbox.init();
+            }
+
+            // trigger the event
+            self.trigger( Galleria.LIGHTBOX_OPEN );
+
+            // temporarily attach some keys
+            // save the old ones first in a cloned object
+            if ( !lightbox.keymap ) {
+
+                lightbox.keymap = $.extend({}, self._keyboard.map);
+
+                self.attachKeyboard({
+                    escape: lightbox.hide,
+                    right: lightbox.showNext,
+                    left: lightbox.showPrev
+                });
+            }
+
+            $win.unbind('resize', lightbox.rescale );
+
+            var data = self.getData(index),
+                total = self.getDataLength(),
+                n = self.getNext( index ),
+                ndata, p, i;
+
+            Utils.hide( lightbox.elems.info );
+
+            try {
+                for ( i = self._options.preload; i > 0; i-- ) {
+                    p = new Galleria.Picture();
+                    ndata = self.getData( n );
+                    p.preload( ndata.big ? ndata.big : ndata.image );
+                    n = self.getNext( n );
+                }
+            } catch(e) {}
+
+            lightbox.image.isIframe = ( data.iframe && !data.image );
+
+            $( lightbox.elems.box ).toggleClass( 'iframe', lightbox.image.isIframe );
+
+            $( lightbox.image.container ).find( '.galleria-videoicon' ).remove();
+
+            lightbox.image.load( data.big || data.image || data.iframe, function( image ) {
+
+                if ( image.isIframe ) {
+
+                    var cw = $(window).width(),
+                        ch = $(window).height();
+
+                    if ( image.video && self._options.maxVideoSize ) {
+                        var r = M.min( self._options.maxVideoSize/cw, self._options.maxVideoSize/ch );
+                        if ( r < 1 ) {
+                            cw *= r;
+                            ch *= r;
+                        }
+                    }
+                    lightbox.width = cw;
+                    lightbox.height = ch;
+
+                } else {
+                    lightbox.width = image.original.width;
+                    lightbox.height = image.original.height;
+                }
+
+                $( image.image ).css({
+                    width: image.isIframe ? '100%' : '100.1%',
+                    height: image.isIframe ? '100%' : '100.1%',
+                    top: 0,
+                    bottom: 0,
+                    zIndex: 99998,
+                    opacity: 0,
+                    visibility: 'visible'
+                }).parent().height('100%');
+
+                lightbox.elems.title.innerHTML = data.title || '';
+                lightbox.elems.counter.innerHTML = (index + 1) + ' / ' + total;
+                $win.resize( lightbox.rescale );
+                lightbox.rescale();
+
+                if( data.image && data.iframe ) {
+
+                    $( lightbox.elems.box ).addClass('iframe');
+
+                    if ( data.video ) {
+                        var $icon = _playIcon( image.container ).hide();
+                        window.setTimeout(function() {
+                            $icon.fadeIn(200);
+                        }, 200);
+                    }
+
+                    $( image.image ).css( 'cursor', 'pointer' ).mouseup((function(data, image) {
+                        return function(e) {
+                            $( lightbox.image.container ).find( '.galleria-videoicon' ).remove();
+                            e.preventDefault();
+                            image.isIframe = true;
+                            image.load( data.iframe + ( data.video ? '&autoplay=1' : '' ), {
+                                width: '100%',
+                                height: IE < 8 ? $( lightbox.image.container ).height() : '100%'
+                            });
+                        };
+                    }(data, image)));
+                }
+            });
+
+            $( lightbox.elems.overlay ).show().css( 'visibility', 'visible' );
+            $( lightbox.elems.box ).show();
+        }
+    };
+
+    // the internal timeouts object
+    // provides helper methods for controlling timeouts
+
+    var _timer = this._timer = {
+
+        trunk: {},
+
+        add: function( id, fn, delay, loop ) {
+            id = id || new Date().getTime();
+            loop = loop || false;
+            this.clear( id );
+            if ( loop ) {
+                var old = fn;
+                fn = function() {
+                    old();
+                    _timer.add( id, fn, delay );
+                };
+            }
+            this.trunk[ id ] = window.setTimeout( fn, delay );
+        },
+
+        clear: function( id ) {
+
+            var del = function( i ) {
+                window.clearTimeout( this.trunk[ i ] );
+                delete this.trunk[ i ];
+            }, i;
+
+            if ( !!id && id in this.trunk ) {
+                del.call( this, id );
+
+            } else if ( typeof id === 'undefined' ) {
+                for ( i in this.trunk ) {
+                    if ( this.trunk.hasOwnProperty( i ) ) {
+                        del.call( this, i );
+                    }
+                }
+            }
+        }
+    };
+
+    return this;
+};
+
+// end Galleria constructor
+
+Galleria.prototype = {
+
+    // bring back the constructor reference
+
+    constructor: Galleria,
+
+    /**
+        Use this function to initialize the gallery and start loading.
+        Should only be called once per instance.
+
+        @param {HTMLElement} target The target element
+        @param {Object} options The gallery options
+
+        @returns Instance
+    */
+
+    init: function( target, options ) {
+
+        options = _legacyOptions( options );
+
+        // save the original ingredients
+        this._original = {
+            target: target,
+            options: options,
+            data: null
+        };
+
+        // save the target here
+        this._target = this._dom.target = target.nodeName ? target : $( target ).get(0);
+
+        // save the original content for destruction
+        this._original.html = this._target.innerHTML;
+
+        // push the instance
+        _instances.push( this );
+
+        // raise error if no target is detected
+        if ( !this._target ) {
+             Galleria.raise('Target not found', true);
+             return;
+        }
+
+        // apply options
+        this._options = {
+            autoplay: false,
+            carousel: true,
+            carouselFollow: true, // legacy, deprecate at 1.3
+            carouselSpeed: 400,
+            carouselSteps: 'auto',
+            clicknext: false,
+            dailymotion: {
+                foreground: '%23EEEEEE',
+                highlight: '%235BCEC5',
+                background: '%23222222',
+                logo: 0,
+                hideInfos: 1
+            },
+            dataConfig : function( elem ) { return {}; },
+            dataSelector: 'img',
+            dataSort: false,
+            dataSource: this._target,
+            debug: undef,
+            dummy: undef, // 1.2.5
+            easing: 'galleria',
+            extend: function(options) {},
+            fullscreenCrop: undef, // 1.2.5
+            fullscreenDoubleTap: true, // 1.2.4 toggles fullscreen on double-tap for touch devices
+            fullscreenTransition: undef, // 1.2.6
+            height: 0,
+            idleMode: true, // 1.2.4 toggles idleMode
+            idleTime: 3000,
+            idleSpeed: 200,
+            imageCrop: false,
+            imageMargin: 0,
+            imagePan: false,
+            imagePanSmoothness: 12,
+            imagePosition: '50%',
+            imageTimeout: undef, // 1.2.5
+            initialTransition: undef, // 1.2.4, replaces transitionInitial
+            keepSource: false,
+            layerFollow: true, // 1.2.5
+            lightbox: false, // 1.2.3
+            lightboxFadeSpeed: 200,
+            lightboxTransitionSpeed: 200,
+            linkSourceImages: true,
+            maxScaleRatio: undef,
+            maxVideoSize: undef, // 1.2.9
+            minScaleRatio: undef, // deprecated in 1.2.9
+            overlayOpacity: 0.85,
+            overlayBackground: '#0b0b0b',
+            pauseOnInteraction: true,
+            popupLinks: false,
+            preload: 2,
+            queue: true,
+            responsive: true,
+            show: 0,
+            showInfo: true,
+            showCounter: true,
+            showImagenav: true,
+            swipe: true, // 1.2.4 -> revised in 1.3
+            thumbCrop: true,
+            thumbEventType: 'click',
+            thumbMargin: 0,
+            thumbQuality: 'auto',
+            thumbDisplayOrder: true, // 1.2.8
+            thumbPosition: '50%', // 1.3
+            thumbnails: true,
+            touchTransition: undef, // 1.2.6
+            transition: 'fade',
+            transitionInitial: undef, // legacy, deprecate in 1.3. Use initialTransition instead.
+            transitionSpeed: 400,
+            trueFullscreen: true, // 1.2.7
+            useCanvas: false, // 1.2.4
+            variation: '', // 1.3.2
+            videoPoster: true, // 1.3
+            vimeo: {
+                title: 0,
+                byline: 0,
+                portrait: 0,
+                color: 'aaaaaa'
+            },
+            wait: 5000, // 1.2.7
+            width: 'auto',
+            youtube: {
+                modestbranding: 1,
+                autohide: 1,
+                color: 'white',
+                hd: 1,
+                rel: 0,
+                showinfo: 0
+            }
+        };
+
+        // legacy support for transitionInitial
+        this._options.initialTransition = this._options.initialTransition || this._options.transitionInitial;
+
+        // turn off debug
+        if ( options && options.debug === false ) {
+            DEBUG = false;
+        }
+
+        // set timeout
+        if ( options && typeof options.imageTimeout === 'number' ) {
+            TIMEOUT = options.imageTimeout;
+        }
+
+        // set dummy
+        if ( options && typeof options.dummy === 'string' ) {
+            DUMMY = options.dummy;
+        }
+
+        // disable swipe if no touch
+        if ( !Galleria.TOUCH ) {
+           this._options.swipe = false;
+        }
+
+        // hide all content
+        $( this._target ).children().hide();
+
+        // Warn for quirks mode
+        if ( Galleria.QUIRK ) {
+            Galleria.raise('Your page is in Quirks mode, Galleria may not render correctly. Please validate your HTML and add a correct doctype.');
+        }
+
+        // now we just have to wait for the theme...
+        if ( typeof Galleria.theme === 'object' ) {
+            this._init();
+        } else {
+            // push the instance into the pool and run it when the theme is ready
+            _pool.push( this );
+        }
+
+        return this;
+    },
+
+    // this method should only be called once per instance
+    // for manipulation of data, use the .load method
+
+    _init: function() {
+
+        var self = this,
+            options = this._options;
+
+        if ( this._initialized ) {
+            Galleria.raise( 'Init failed: Gallery instance already initialized.' );
+            return this;
+        }
+
+        this._initialized = true;
+
+        if ( !Galleria.theme ) {
+            Galleria.raise( 'Init failed: No theme found.', true );
+            return this;
+        }
+
+        // merge the theme & caller options
+        $.extend( true, options, Galleria.theme.defaults, this._original.options, Galleria.configure.options );
+
+        // disable options that arent compatible with swipe
+        if ( options.swipe ) {
+            options.clicknext = false;
+            options.imagePan = false;
+        }
+
+        // check for canvas support
+        (function( can ) {
+
+            if ( !( 'getContext' in can ) ) {
+                can = null;
+                return;
+            }
+
+            _canvas = _canvas || {
+                elem: can,
+                context: can.getContext( '2d' ),
+                cache: {},
+                length: 0
+            };
+
+        }( doc.createElement( 'canvas' ) ) );
+
+
+        Galleria.Fastclick.init( this.get('target' ));
+
+        // bind the gallery to run when data is ready
+        this.bind( Galleria.DATA, function() {
+
+            // remove big if total pixels are less than 1024 (most phones)
+            if ( window.screen && window.screen.width && Array.prototype.forEach ) {
+
+                this._data.forEach(function(data) {
+
+                    var density = 'devicePixelRatio' in window ? window.devicePixelRatio : 1,
+                        m = M.max( window.screen.width, window.screen.height );
+
+                    if ( m*density < 1024 ) {
+                        data.big = data.image;
+                    }
+                });
+            }
+
+            // save the new data
+            this._original.data = this._data;
+
+            // lets show the counter here
+            this.get('total').innerHTML = this.getDataLength();
+
+            // cache the container
+            var $container = this.$( 'container' );
+
+            // set ratio if height is < 2
+            if ( self._options.height < 2 ) {
+                self._userRatio = self._ratio = self._options.height;
+            }
+
+            // the gallery is ready, let's just wait for the css
+            var num = { width: 0, height: 0 };
+            var testHeight = function() {
+                return self.$( 'stage' ).height();
+            };
+
+            // check container and thumbnail height
+            Utils.wait({
+                until: function() {
+
+                    // keep trying to get the value
+                    num = self._getWH();
+                    $container.width( num.width ).height( num.height );
+                    return testHeight() && num.width && num.height > 50;
+
+                },
+                success: function() {
+
+                    self._width = num.width;
+                    self._height = num.height;
+                    self._ratio = self._ratio || num.height/num.width;
+
+                    // for some strange reason, webkit needs a single setTimeout to play ball
+                    if ( Galleria.WEBKIT ) {
+                        window.setTimeout( function() {
+                            self._run();
+                        }, 1);
+                    } else {
+                        self._run();
+                    }
+                },
+                error: function() {
+
+                    // Height was probably not set, raise hard errors
+
+                    if ( testHeight() ) {
+                        Galleria.raise('Could not extract sufficient width/height of the gallery container. Traced measures: width:' + num.width + 'px, height: ' + num.height + 'px.', true);
+                    } else {
+                        Galleria.raise('Could not extract a stage height from the CSS. Traced height: ' + testHeight() + 'px.', true);
+                    }
+                },
+                timeout: typeof this._options.wait == 'number' ? this._options.wait : false
+            });
+        });
+
+        // build the gallery frame
+        this.append({
+            'info-text' :
+                ['info-title', 'info-description'],
+            'info' :
+                ['info-text'],
+            'image-nav' :
+                ['image-nav-right', 'image-nav-left'],
+            'stage' :
+                ['images', 'loader', 'counter', 'image-nav'],
+            'thumbnails-list' :
+                ['thumbnails'],
+            'thumbnails-container' :
+                ['thumb-nav-left', 'thumbnails-list', 'thumb-nav-right'],
+            'container' :
+                ['stage', 'thumbnails-container', 'info', 'tooltip']
+        });
+
+        Utils.hide( this.$( 'counter' ).append(
+            this.get( 'current' ),
+            doc.createTextNode(' / '),
+            this.get( 'total' )
+        ) );
+
+        this.setCounter('–');
+
+        Utils.hide( self.get('tooltip') );
+
+        // add a notouch class on the container to prevent unwanted :hovers on touch devices
+        this.$( 'container' ).addClass( ( Galleria.TOUCH ? 'touch' : 'notouch' ) + ' ' + this._options.variation );
+
+        // add images to the controls
+        if ( !this._options.swipe ) {
+            $.each( new Array(2), function( i ) {
+
+                // create a new Picture instance
+                var image = new Galleria.Picture();
+
+                // apply some styles, create & prepend overlay
+                $( image.container ).css({
+                    position: 'absolute',
+                    top: 0,
+                    left: 0
+                }).prepend( self._layers[i] = $( Utils.create('galleria-layer') ).css({
+                    position: 'absolute',
+                    top:0, left:0, right:0, bottom:0,
+                    zIndex:2
+                })[0] );
+
+                // append the image
+                self.$( 'images' ).append( image.container );
+
+                // reload the controls
+                self._controls[i] = image;
+
+                // build a frame
+                var frame = new Galleria.Picture();
+                frame.isIframe = true;
+
+                $( frame.container ).attr('class', 'galleria-frame').css({
+                    position: 'absolute',
+                    top: 0,
+                    left: 0,
+                    zIndex: 4,
+                    background: '#000',
+                    display: 'none'
+                }).appendTo( image.container );
+
+                self._controls.frames[i] = frame;
+
+            });
+        }
+
+        // some forced generic styling
+        this.$( 'images' ).css({
+            position: 'relative',
+            top: 0,
+            left: 0,
+            width: '100%',
+            height: '100%'
+        });
+
+        if ( options.swipe ) {
+            this.$( 'images' ).css({
+                position: 'absolute',
+                top: 0,
+                left: 0,
+                width: 0,
+                height: '100%'
+            });
+            this.finger = new Galleria.Finger(this.get('stage'), {
+                onchange: function(page) {
+                    self.setCounter( page );
+                    self.pause();
+                    self.show(page);
+                },
+                oncomplete: function(page) {
+
+                    var index = M.max( 0, M.min( parseInt( page, 10 ), self.getDataLength() - 1 ) ),
+                        data = self.getData(index);
+
+                    if ( !data ) {
+                       return;
+                    }
+
+                    self.$( 'images' ).find( 'iframe' ).remove();
+                    self.$( 'images' ).find( '.galleria-frame' ).css('opacity', 0).hide();
+
+                    var src = self.isFullscreen() && data.big ? data.big : ( data.image || data.iframe ),
+                        image = self._controls.slides[index],
+                        cached = image.isCached( src ),
+                        thumb = self._thumbnails[ index ];
+
+                    self.trigger({
+                        type: Galleria.IMAGE,
+                        cached: cached,
+                        index: index,
+                        imageTarget: image.image,
+                        thumbTarget: thumb.image,
+                        galleriaData: data
+                    });
+
+                    if ( self._options.carousel && self._options.carouselFollow ) {
+                        self._carousel.follow( index );
+                    }
+                }
+            });
+            this.bind( Galleria.RESCALE, function() {
+                this.finger.setup();
+            });
+            this.$('stage').bind('click', function(e) {
+                var data = self.getData();
+                if ( !data ) {
+                    return;
+                }
+                if ( data.iframe ) {
+
+                    if ( self.isPlaying() ) {
+                        self.pause();
+                    }
+                    var frame = self._controls.frames[ self._active ],
+                        w = self._stageWidth,
+                        h = self._stageHeight;
+
+                    if ( $( frame.container ).find( 'iframe' ).length ) {
+                        return;
+                    }
+
+                    $( frame.container ).css({
+                        width: w,
+                        height: h,
+                        opacity: 0
+                    }).show().animate({
+                        opacity: 1
+                    }, 200);
+
+                    window.setTimeout(function() {
+                        frame.load( data.iframe + ( data.video ? '&autoplay=1' : '' ), {
+                            width: w,
+                            height: h
+                        }, function( frame ) {
+                            self.$( 'container' ).addClass( 'videoplay' );
+                            frame.scale({
+                                width: self._stageWidth,
+                                height: self._stageHeight,
+                                iframelimit: data.video ? self._options.maxVideoSize : undef
+                            });
+                        });
+                    }, 100);
+
+                    return;
+                }
+
+                if ( data.link ) {
+                    if ( self._options.popupLinks ) {
+                        var win = window.open( data.link, '_blank' );
+                    } else {
+                        window.location.href = data.link;
+                    }
+                    return;
+                }
+            });
+            this.bind( Galleria.IMAGE, function(e) {
+
+                self.setCounter( e.index );
+                self.setInfo( e.index );
+
+                var next = this.getNext(),
+                    prev = this.getPrev();
+
+                var preloads = [prev,next];
+                preloads.push(this.getNext(next), this.getPrev(prev), self._controls.slides.length-1);
+
+                var filtered = [];
+
+                $.each(preloads, function(i, val) {
+                    if ( $.inArray(val, filtered) == -1 ) {
+                        filtered.push(val);
+                    }
+                });
+
+                $.each(filtered, function(i, loadme) {
+                    var d = self.getData(loadme),
+                        img = self._controls.slides[loadme],
+                        src = self.isFullscreen() && d.big ? d.big : ( d.image || d.iframe );
+
+                    if ( d.iframe && !d.image ) {
+                        img.isIframe = true;
+                    }
+
+                    if ( !img.ready ) {
+                        self._controls.slides[loadme].load(src, function(img) {
+                            if ( !img.isIframe ) {
+                                $(img.image).css('visibility', 'hidden');
+                            }
+                            self._scaleImage(img, {
+                                complete: function(img) {
+                                    if ( !img.isIframe ) {
+                                        $(img.image).css({
+                                            opacity: 0,
+                                            visibility: 'visible'
+                                        }).animate({
+                                            opacity: 1
+                                        }, 200);
+                                    }
+                                }
+                            });
+                        });
+                    }
+                });
+            });
+        }
+
+        this.$( 'thumbnails, thumbnails-list' ).css({
+            overflow: 'hidden',
+            position: 'relative'
+        });
+
+        // bind image navigation arrows
+        this.$( 'image-nav-right, image-nav-left' ).bind( 'click', function(e) {
+
+            // tune the clicknext option
+            if ( options.clicknext ) {
+                e.stopPropagation();
+            }
+
+            // pause if options is set
+            if ( options.pauseOnInteraction ) {
+                self.pause();
+            }
+
+            // navigate
+            var fn = /right/.test( this.className ) ? 'next' : 'prev';
+            self[ fn ]();
+
+        });
+
+        // hide controls if chosen to
+        $.each( ['info','counter','image-nav'], function( i, el ) {
+            if ( options[ 'show' + el.substr(0,1).toUpperCase() + el.substr(1).replace(/-/,'') ] === false ) {
+                Utils.moveOut( self.get( el.toLowerCase() ) );
+            }
+        });
+
+        // load up target content
+        this.load();
+
+        // now it's usually safe to remove the content
+        // IE will never stop loading if we remove it, so let's keep it hidden for IE (it's usually fast enough anyway)
+        if ( !options.keepSource && !IE ) {
+            this._target.innerHTML = '';
+        }
+
+        // re-append the errors, if they happened before clearing
+        if ( this.get( 'errors' ) ) {
+            this.appendChild( 'target', 'errors' );
+        }
+
+        // append the gallery frame
+        this.appendChild( 'target', 'container' );
+
+        // parse the carousel on each thumb load
+        if ( options.carousel ) {
+            var count = 0,
+                show = options.show;
+            this.bind( Galleria.THUMBNAIL, function() {
+                this.updateCarousel();
+                if ( ++count == this.getDataLength() && typeof show == 'number' && show > 0 ) {
+                    this._carousel.follow( show );
+                }
+            });
+        }
+
+        // bind window resize for responsiveness
+        if ( options.responsive ) {
+            $win.bind( 'resize', function() {
+                if ( !self.isFullscreen() ) {
+                    self.resize();
+                }
+            });
+        }
+
+        // double-tap/click fullscreen toggle
+
+        if ( options.fullscreenDoubleTap ) {
+
+            this.$( 'stage' ).bind( 'touchstart', (function() {
+                var last, cx, cy, lx, ly, now,
+                    getData = function(e) {
+                        return e.originalEvent.touches ? e.originalEvent.touches[0] : e;
+                    };
+                self.$( 'stage' ).bind('touchmove', function() {
+                    last = 0;
+                });
+                return function(e) {
+                    if( /(-left|-right)/.test(e.target.className) ) {
+                        return;
+                    }
+                    now = Utils.timestamp();
+                    cx = getData(e).pageX;
+                    cy = getData(e).pageY;
+                    if ( e.originalEvent.touches.length < 2 && ( now - last < 300 ) && ( cx - lx < 20) && ( cy - ly < 20) ) {
+                        self.toggleFullscreen();
+                        e.preventDefault();
+                        return;
+                    }
+                    last = now;
+                    lx = cx;
+                    ly = cy;
+                };
+            }()));
+        }
+
+        // bind the ons
+        $.each( Galleria.on.binds, function(i, bind) {
+            // check if already bound
+            if ( $.inArray( bind.hash, self._binds ) == -1 ) {
+                self.bind( bind.type, bind.callback );
+            }
+        });
+
+        return this;
+    },
+
+    addTimer : function() {
+        this._timer.add.apply( this._timer, Utils.array( arguments ) );
+        return this;
+    },
+
+    clearTimer : function() {
+        this._timer.clear.apply( this._timer, Utils.array( arguments ) );
+        return this;
+    },
+
+    // parse width & height from CSS or options
+
+    _getWH : function() {
+
+        var $container = this.$( 'container' ),
+            $target = this.$( 'target' ),
+            self = this,
+            num = {},
+            arr;
+
+        $.each(['width', 'height'], function( i, m ) {
+
+            // first check if options is set
+            if ( self._options[ m ] && typeof self._options[ m ] === 'number') {
+                num[ m ] = self._options[ m ];
+            } else {
+
+                arr = [
+                    Utils.parseValue( $container.css( m ) ),         // the container css height
+                    Utils.parseValue( $target.css( m ) ),            // the target css height
+                    $container[ m ](),                               // the container jQuery method
+                    $target[ m ]()                                   // the target jQuery method
+                ];
+
+                // if first time, include the min-width & min-height
+                if ( !self[ '_'+m ] ) {
+                    arr.splice(arr.length,
+                        Utils.parseValue( $container.css( 'min-'+m ) ),
+                        Utils.parseValue( $target.css( 'min-'+m ) )
+                    );
+                }
+
+                // else extract the measures from different sources and grab the highest value
+                num[ m ] = M.max.apply( M, arr );
+            }
+        });
+
+        // allow setting a height ratio instead of exact value
+        // useful when doing responsive galleries
+
+        if ( self._userRatio ) {
+            num.height = num.width * self._userRatio;
+        }
+
+        return num;
+    },
+
+    // Creates the thumbnails and carousel
+    // can be used at any time, f.ex when the data object is manipulated
+    // push is an optional argument with pushed images
+
+    _createThumbnails : function( push ) {
+
+        this.get( 'total' ).innerHTML = this.getDataLength();
+
+        var src,
+            thumb,
+            data,
+
+            $container,
+
+            self = this,
+            o = this._options,
+
+            i = push ? this._data.length - push.length : 0,
+            chunk = i,
+
+            thumbchunk = [],
+            loadindex = 0,
+
+            gif = IE < 8 ? 'http://upload.wikimedia.org/wikipedia/commons/c/c0/Blank.gif' :
+                           'data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw%3D%3D',
+
+            // get previously active thumbnail, if exists
+            active = (function() {
+                var a = self.$('thumbnails').find('.active');
+                if ( !a.length ) {
+                    return false;
+                }
+                return a.find('img').attr('src');
+            }()),
+
+            // cache the thumbnail option
+            optval = typeof o.thumbnails === 'string' ? o.thumbnails.toLowerCase() : null,
+
+            // move some data into the instance
+            // for some reason, jQuery cant handle css(property) when zooming in FF, breaking the gallery
+            // so we resort to getComputedStyle for browsers who support it
+            getStyle = function( prop ) {
+                return doc.defaultView && doc.defaultView.getComputedStyle ?
+                    doc.defaultView.getComputedStyle( thumb.container, null )[ prop ] :
+                    $container.css( prop );
+            },
+
+            fake = function(image, index, container) {
+                return function() {
+                    $( container ).append( image );
+                    self.trigger({
+                        type: Galleria.THUMBNAIL,
+                        thumbTarget: image,
+                        index: index,
+                        galleriaData: self.getData( index )
+                    });
+                };
+            },
+
+            onThumbEvent = function( e ) {
+
+                // pause if option is set
+                if ( o.pauseOnInteraction ) {
+                    self.pause();
+                }
+
+                // extract the index from the data
+                var index = $( e.currentTarget ).data( 'index' );
+                if ( self.getIndex() !== index ) {
+                    self.show( index );
+                }
+
+                e.preventDefault();
+            },
+
+            thumbComplete = function( thumb, callback ) {
+
+                $( thumb.container ).css( 'visibility', 'visible' );
+                self.trigger({
+                    type: Galleria.THUMBNAIL,
+                    thumbTarget: thumb.image,
+                    index: thumb.data.order,
+                    galleriaData: self.getData( thumb.data.order )
+                });
+
+                if ( typeof callback == 'function' ) {
+                    callback.call( self, thumb );
+                }
+            },
+
+            onThumbLoad = function( thumb, callback ) {
+
+                // scale when ready
+                thumb.scale({
+                    width:    thumb.data.width,
+                    height:   thumb.data.height,
+                    crop:     o.thumbCrop,
+                    margin:   o.thumbMargin,
+                    canvas:   o.useCanvas,
+                    position: o.thumbPosition,
+                    complete: function( thumb ) {
+
+                        // shrink thumbnails to fit
+                        var top = ['left', 'top'],
+                            arr = ['Width', 'Height'],
+                            m,
+                            css,
+                            data = self.getData( thumb.index );
+
+                        // calculate shrinked positions
+                        $.each(arr, function( i, measure ) {
+                            m = measure.toLowerCase();
+                            if ( (o.thumbCrop !== true || o.thumbCrop === m ) ) {
+                                css = {};
+                                css[ m ] = thumb[ m ];
+                                $( thumb.container ).css( css );
+                                css = {};
+                                css[ top[ i ] ] = 0;
+                                $( thumb.image ).css( css );
+                            }
+
+                            // cache outer measures
+                            thumb[ 'outer' + measure ] = $( thumb.container )[ 'outer' + measure ]( true );
+                        });
+
+                        // set high quality if downscale is moderate
+                        Utils.toggleQuality( thumb.image,
+                            o.thumbQuality === true ||
+                            ( o.thumbQuality === 'auto' && thumb.original.width < thumb.width * 3 )
+                        );
+
+                        if ( o.thumbDisplayOrder && !thumb.lazy ) {
+
+                            $.each( thumbchunk, function( i, th ) {
+                                if ( i === loadindex && th.ready && !th.displayed ) {
+
+                                    loadindex++;
+                                    th.displayed = true;
+
+                                    thumbComplete( th, callback );
+
+                                    return;
+                                }
+                            });
+                        } else {
+                            thumbComplete( thumb, callback );
+                        }
+                    }
+                });
+            };
+
+        if ( !push ) {
+            this._thumbnails = [];
+            this.$( 'thumbnails' ).empty();
+        }
+
+        // loop through data and create thumbnails
+        for( ; this._data[ i ]; i++ ) {
+
+            data = this._data[ i ];
+
+            // get source from thumb or image
+            src = data.thumb || data.image;
+
+            if ( ( o.thumbnails === true || optval == 'lazy' ) && ( data.thumb || data.image ) ) {
+
+                // add a new Picture instance
+                thumb = new Galleria.Picture(i);
+
+                // save the index
+                thumb.index = i;
+
+                // flag displayed
+                thumb.displayed = false;
+
+                // flag lazy
+                thumb.lazy = false;
+
+                // flag video
+                thumb.video = false;
+
+                // append the thumbnail
+                this.$( 'thumbnails' ).append( thumb.container );
+
+                // cache the container
+                $container = $( thumb.container );
+
+                // hide it
+                $container.css( 'visibility', 'hidden' );
+
+                thumb.data = {
+                    width  : Utils.parseValue( getStyle( 'width' ) ),
+                    height : Utils.parseValue( getStyle( 'height' ) ),
+                    order  : i,
+                    src    : src
+                };
+
+                // grab & reset size for smoother thumbnail loads
+                if ( o.thumbCrop !== true ) {
+                    $container.css( { width: 'auto', height: 'auto' } );
+                } else {
+                    $container.css( { width: thumb.data.width, height: thumb.data.height } );
+                }
+
+                // load the thumbnail
+                if ( optval == 'lazy' ) {
+
+                    $container.addClass( 'lazy' );
+
+                    thumb.lazy = true;
+
+                    thumb.load( gif, {
+                        height: thumb.data.height,
+                        width: thumb.data.width
+                    });
+
+                } else {
+                    thumb.load( src, onThumbLoad );
+                }
+
+                // preload all images here
+                if ( o.preload === 'all' ) {
+                    thumb.preload( data.image );
+                }
+
+            // create empty spans if thumbnails is set to 'empty'
+            } else if ( data.iframe || optval === 'empty' || optval === 'numbers' ) {
+
+                thumb = {
+                    container: Utils.create( 'galleria-image' ),
+                    image: Utils.create( 'img', 'span' ),
+                    ready: true,
+                    data: {
+                        order: i
+                    }
+                };
+
+                // create numbered thumbnails
+                if ( optval === 'numbers' ) {
+                    $( thumb.image ).text( i + 1 );
+                }
+
+                if ( data.iframe ) {
+                    $( thumb.image ).addClass( 'iframe' );
+                }
+
+                this.$( 'thumbnails' ).append( thumb.container );
+
+                // we need to "fake" a loading delay before we append and trigger
+                // 50+ should be enough
+
+                window.setTimeout( ( fake )( thumb.image, i, thumb.container ), 50 + ( i*20 ) );
+
+            // create null object to silent errors
+            } else {
+                thumb = {
+                    container: null,
+                    image: null
+                };
+            }
+
+            // add events for thumbnails
+            // you can control the event type using thumb_event_type
+            // we'll add the same event to the source if it's kept
+
+            $( thumb.container ).add( o.keepSource && o.linkSourceImages ? data.original : null )
+                .data('index', i).bind( o.thumbEventType, onThumbEvent )
+                .data('thumbload', onThumbLoad);
+
+            if (active === src) {
+                $( thumb.container ).addClass( 'active' );
+            }
+
+            this._thumbnails.push( thumb );
+        }
+
+        thumbchunk = this._thumbnails.slice( chunk );
+
+        return this;
+    },
+
+    /**
+        Lazy-loads thumbnails.
+        You can call this method to load lazy thumbnails at run time
+
+        @param {Array|Number} index Index or array of indexes of thumbnails to be loaded
+        @param {Function} complete Callback that is called when all lazy thumbnails have been loaded
+
+        @returns Instance
+    */
+
+    lazyLoad: function( index, complete ) {
+
+        var arr = index.constructor == Array ? index : [ index ],
+            self = this,
+            loaded = 0;
+
+        $.each( arr, function(i, ind) {
+
+            if ( ind > self._thumbnails.length - 1 ) {
+                return;
+            }
+
+            var thumb = self._thumbnails[ ind ],
+                data = thumb.data,
+                callback = function() {
+                    if ( ++loaded == arr.length && typeof complete == 'function' ) {
+                        complete.call( self );
+                    }
+                },
+                thumbload = $( thumb.container ).data( 'thumbload' );
+            if ( thumb.video ) {
+                thumbload.call( self, thumb, callback );
+            } else {
+                thumb.load( data.src , function( thumb ) {
+                    thumbload.call( self, thumb, callback );
+                });
+            }
+        });
+
+        return this;
+
+    },
+
+    /**
+        Lazy-loads thumbnails in chunks.
+        This method automatcally chops up the loading process of many thumbnails into chunks
+
+        @param {Number} size Size of each chunk to be loaded
+        @param {Number} [delay] Delay between each loads
+
+        @returns Instance
+    */
+
+    lazyLoadChunks: function( size, delay ) {
+
+        var len = this.getDataLength(),
+            i = 0,
+            n = 0,
+            arr = [],
+            temp = [],
+            self = this;
+
+        delay = delay || 0;
+
+        for( ; i<len; i++ ) {
+            temp.push(i);
+            if ( ++n == size || i == len-1 ) {
+                arr.push( temp );
+                n = 0;
+                temp = [];
+            }
+        }
+
+        var init = function( wait ) {
+            var a = arr.shift();
+            if ( a ) {
+                window.setTimeout(function() {
+                    self.lazyLoad(a, function() {
+                        init( true );
+                    });
+                }, ( delay && wait ) ? delay : 0 );
+            }
+        };
+
+        init( false );
+
+        return this;
+
+    },
+
+    // the internal _run method should be called after loading data into galleria
+    // makes sure the gallery has proper measurements before postrun & ready
+    _run : function() {
+
+        var self = this;
+
+        self._createThumbnails();
+
+        // make sure we have a stageHeight && stageWidth
+
+        Utils.wait({
+
+            timeout: 10000,
+
+            until: function() {
+
+                // Opera crap
+                if ( Galleria.OPERA ) {
+                    self.$( 'stage' ).css( 'display', 'inline-block' );
+                }
+
+                self._stageWidth  = self.$( 'stage' ).width();
+                self._stageHeight = self.$( 'stage' ).height();
+
+                return( self._stageWidth &&
+                        self._stageHeight > 50 ); // what is an acceptable height?
+            },
+
+            success: function() {
+
+                // save the instance
+                _galleries.push( self );
+
+                // postrun some stuff after the gallery is ready
+
+                // create the touch slider
+                if ( self._options.swipe ) {
+
+                    var $images = self.$( 'images' ).width( self.getDataLength() * self._stageWidth );
+                    $.each( new Array( self.getDataLength() ), function(i) {
+
+                        var image = new Galleria.Picture(),
+                            data = self.getData(i);
+
+                        $( image.container ).css({
+                            position: 'absolute',
+                            top: 0,
+                            left: self._stageWidth*i
+                        }).prepend( self._layers[i] = $( Utils.create('galleria-layer') ).css({
+                            position: 'absolute',
+                            top:0, left:0, right:0, bottom:0,
+                            zIndex:2
+                        })[0] ).appendTo( $images );
+
+                        if( data.video ) {
+                            _playIcon( image.container );
+                        }
+
+                        self._controls.slides.push(image);
+
+                        var frame = new Galleria.Picture();
+                        frame.isIframe = true;
+
+                        $( frame.container ).attr('class', 'galleria-frame').css({
+                            position: 'absolute',
+                            top: 0,
+                            left: 0,
+                            zIndex: 4,
+                            background: '#000',
+                            display: 'none'
+                        }).appendTo( image.container );
+
+                        self._controls.frames.push(frame);
+                    });
+
+                    self.finger.setup();
+                }
+
+                // show counter
+                Utils.show( self.get('counter') );
+
+                // bind carousel nav
+                if ( self._options.carousel ) {
+                    self._carousel.bindControls();
+                }
+
+                // start autoplay
+                if ( self._options.autoplay ) {
+
+                    self.pause();
+
+                    if ( typeof self._options.autoplay === 'number' ) {
+                        self._playtime = self._options.autoplay;
+                    }
+
+                    self._playing = true;
+                }
+                // if second load, just do the show and return
+                if ( self._firstrun ) {
+
+                    if ( self._options.autoplay ) {
+                        self.trigger( Galleria.PLAY );
+                    }
+
+                    if ( typeof self._options.show === 'number' ) {
+                        self.show( self._options.show );
+                    }
+                    return;
+                }
+
+                self._firstrun = true;
+
+                // initialize the History plugin
+                if ( Galleria.History ) {
+
+                    // bind the show method
+                    Galleria.History.change(function( value ) {
+
+                        // if ID is NaN, the user pressed back from the first image
+                        // return to previous address
+                        if ( isNaN( value ) ) {
+                            window.history.go(-1);
+
+                        // else show the image
+                        } else {
+                            self.show( value, undef, true );
+                        }
+                    });
+                }
+
+                self.trigger( Galleria.READY );
+
+                // call the theme init method
+                Galleria.theme.init.call( self, self._options );
+
+                // Trigger Galleria.ready
+                $.each( Galleria.ready.callbacks, function(i ,fn) {
+                    if ( typeof fn == 'function' ) {
+                        fn.call( self, self._options );
+                    }
+                });
+                Galleria.ready.callbacks = [];
+
+                // call the extend option
+                self._options.extend.call( self, self._options );
+
+                // show the initial image
+                // first test for permalinks in history
+                if ( /^[0-9]{1,4}$/.test( HASH ) && Galleria.History ) {
+                    self.show( HASH, undef, true );
+
+                } else if( self._data[ self._options.show ] ) {
+                    self.show( self._options.show );
+                }
+
+                // play trigger
+                if ( self._options.autoplay ) {
+                    self.trigger( Galleria.PLAY );
+                }
+            },
+
+            error: function() {
+                Galleria.raise('Stage width or height is too small to show the gallery. Traced measures: width:' + self._stageWidth + 'px, height: ' + self._stageHeight + 'px.', true);
+            }
+
+        });
+    },
+
+    /**
+        Loads data into the gallery.
+        You can call this method on an existing gallery to reload the gallery with new data.
+
+        @param {Array|string} [source] Optional JSON array of data or selector of where to find data in the document.
+        Defaults to the Galleria target or dataSource option.
+
+        @param {string} [selector] Optional element selector of what elements to parse.
+        Defaults to 'img'.
+
+        @param {Function} [config] Optional function to modify the data extraction proceedure from the selector.
+        See the dataConfig option for more information.
+
+        @returns Instance
+    */
+
+    load : function( source, selector, config ) {
+
+        var self = this,
+            o = this._options;
+
+        // empty the data array
+        this._data = [];
+
+        // empty the thumbnails
+        this._thumbnails = [];
+        this.$('thumbnails').empty();
+
+        // shorten the arguments
+        if ( typeof selector === 'function' ) {
+            config = selector;
+            selector = null;
+        }
+
+        // use the source set by target
+        source = source || o.dataSource;
+
+        // use selector set by option
+        selector = selector || o.dataSelector;
+
+        // use the dataConfig set by option
+        config = config || o.dataConfig;
+
+        // if source is a true object, make it into an array
+        if( $.isPlainObject( source ) ) {
+            source = [source];
+        }
+
+        // check if the data is an array already
+        if ( $.isArray( source ) ) {
+            if ( this.validate( source ) ) {
+                this._data = source;
+            } else {
+                Galleria.raise( 'Load failed: JSON Array not valid.' );
+            }
+        } else {
+
+            // add .video and .iframe to the selector (1.2.7)
+            selector += ',.video,.iframe';
+
+            // loop through images and set data
+            $( source ).find( selector ).each( function( i, elem ) {
+
+                elem = $( elem );
+                var data = {},
+                    parent = elem.parent(),
+                    href = parent.attr( 'href' ),
+                    rel  = parent.attr( 'rel' );
+
+                if( href && ( elem[0].nodeName == 'IMG' || elem.hasClass('video') ) && _videoTest( href ) ) {
+                    data.video = href;
+                } else if( href && elem.hasClass('iframe') ) {
+                    data.iframe = href;
+                } else {
+                    data.image = data.big = href;
+                }
+
+                if ( rel ) {
+                    data.big = rel;
+                }
+
+                // alternative extraction from HTML5 data attribute, added in 1.2.7
+                $.each( 'big title description link layer image'.split(' '), function( i, val ) {
+                    if ( elem.data(val) ) {
+                        data[ val ] = elem.data(val).toString();
+                    }
+                });
+
+                if ( !data.big ) {
+                    data.big = data.image;
+                }
+
+                // mix default extractions with the hrefs and config
+                // and push it into the data array
+                self._data.push( $.extend({
+
+                    title:       elem.attr('title') || '',
+                    thumb:       elem.attr('src'),
+                    image:       elem.attr('src'),
+                    big:         elem.attr('src'),
+                    description: elem.attr('alt') || '',
+                    link:        elem.attr('longdesc'),
+                    original:    elem.get(0) // saved as a reference
+
+                }, data, config( elem ) ) );
+
+            });
+        }
+
+        if ( typeof o.dataSort == 'function' ) {
+            protoArray.sort.call( this._data, o.dataSort );
+        } else if ( o.dataSort == 'random' ) {
+            this._data.sort( function() {
+                return M.round(M.random())-0.5;
+            });
+        }
+
+        // trigger the DATA event and return
+        if ( this.getDataLength() ) {
+            this._parseData( function() {
+                this.trigger( Galleria.DATA );
+            } );
+        }
+        return this;
+
+    },
+
+    // make sure the data works properly
+    _parseData : function( callback ) {
+
+        var self = this,
+            current,
+            ready = false,
+            onload = function() {
+                var complete = true;
+                $.each( self._data, function( i, data ) {
+                    if ( data.loading ) {
+                        complete = false;
+                        return false;
+                    }
+                });
+                if ( complete && !ready ) {
+                    ready = true;
+                    callback.call( self );
+                }
+            };
+
+        $.each( this._data, function( i, data ) {
+
+            current = self._data[ i ];
+
+            // copy image as thumb if no thumb exists
+            if ( 'thumb' in data === false ) {
+                current.thumb = data.image;
+            }
+            // copy image as big image if no biggie exists
+            if ( !data.big ) {
+                current.big = data.image;
+            }
+            // parse video
+            if ( 'video' in data ) {
+                var result = _videoTest( data.video );
+
+                if ( result ) {
+                    current.iframe = new Video(result.provider, result.id ).embed() + (function() {
+
+                        // add options
+                        if ( typeof self._options[ result.provider ] == 'object' ) {
+                            var str = '?', arr = [];
+                            $.each( self._options[ result.provider ], function( key, val ) {
+                                arr.push( key + '=' + val );
+                            });
+
+                            // small youtube specifics, perhaps move to _video later
+                            if ( result.provider == 'youtube' ) {
+                                arr = ['wmode=opaque'].concat(arr);
+                            }
+                            return str + arr.join('&');
+                        }
+                        return '';
+                    }());
+
+                    // pre-fetch video providers media
+
+                    if( !current.thumb || !current.image ) {
+                        $.each( ['thumb', 'image'], function( i, type ) {
+                            if ( type == 'image' && !self._options.videoPoster ) {
+                                current.image = undef;
+                                return;
+                            }
+                            var video = new Video( result.provider, result.id );
+                            if ( !current[ type ] ) {
+                                current.loading = true;
+                                video.getMedia( type, (function(current, type) {
+                                    return function(src) {
+                                        current[ type ] = src;
+                                        if ( type == 'image' && !current.big ) {
+                                            current.big = current.image;
+                                        }
+                                        delete current.loading;
+                                        onload();
+                                    };
+                                }( current, type )));
+                            }
+                        });
+                    }
+                }
+            }
+        });
+
+        onload();
+
+        return this;
+    },
+
+    /**
+        Destroy the Galleria instance and recover the original content
+
+        @example this.destroy();
+
+        @returns Instance
+    */
+
+    destroy : function() {
+        this.$( 'target' ).data( 'galleria', null );
+        this.$( 'container' ).unbind( 'galleria' );
+        this.get( 'target' ).innerHTML = this._original.html;
+        this.clearTimer();
+        Utils.removeFromArray( _instances, this );
+        Utils.removeFromArray( _galleries, this );
+        if ( Galleria._waiters.length ) {
+            $.each( Galleria._waiters, function( i, w ) {
+                if ( w ) window.clearTimeout( w );
+            });
+        }
+        return this;
+    },
+
+    /**
+        Adds and/or removes images from the gallery
+        Works just like Array.splice
+        https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice
+
+        @example this.splice( 2, 4 ); // removes 4 images after the second image
+
+        @returns Instance
+    */
+
+    splice : function() {
+        var self = this,
+            args = Utils.array( arguments );
+        window.setTimeout(function() {
+            protoArray.splice.apply( self._data, args );
+            self._parseData( function() {
+                self._createThumbnails();
+            });
+        },2);
+        return self;
+    },
+
+    /**
+        Append images to the gallery
+        Works just like Array.push
+        https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/push
+
+        @example this.push({ image: 'image1.jpg' }); // appends the image to the gallery
+
+        @returns Instance
+    */
+
+    push : function() {
+        var self = this,
+            args = Utils.array( arguments );
+
+        if ( args.length == 1 && args[0].constructor == Array ) {
+            args = args[0];
+        }
+
+        window.setTimeout(function() {
+            protoArray.push.apply( self._data, args );
+            self._parseData( function() {
+                self._createThumbnails( args );
+            });
+        }, 2);
+        return self;
+    },
+
+    _getActive : function() {
+        return this._controls.getActive();
+    },
+
+    validate : function( data ) {
+        // todo: validate a custom data array
+        return true;
+    },
+
+    /**
+        Bind any event to Galleria
+
+        @param {string} type The Event type to listen for
+        @param {Function} fn The function to execute when the event is triggered
+
+        @example this.bind( 'image', function() { Galleria.log('image shown') });
+
+        @returns Instance
+    */
+
+    bind : function(type, fn) {
+
+        // allow 'image' instead of Galleria.IMAGE
+        type = _patchEvent( type );
+
+        this.$( 'container' ).bind( type, this.proxy(fn) );
+        return this;
+    },
+
+    /**
+        Unbind any event to Galleria
+
+        @param {string} type The Event type to forget
+
+        @returns Instance
+    */
+
+    unbind : function(type) {
+
+        type = _patchEvent( type );
+
+        this.$( 'container' ).unbind( type );
+        return this;
+    },
+
+    /**
+        Manually trigger a Galleria event
+
+        @param {string} type The Event to trigger
+
+        @returns Instance
+    */
+
+    trigger : function( type ) {
+
+        type = typeof type === 'object' ?
+            $.extend( type, { scope: this } ) :
+            { type: _patchEvent( type ), scope: this };
+
+        this.$( 'container' ).trigger( type );
+
+        return this;
+    },
+
+    /**
+        Assign an "idle state" to any element.
+        The idle state will be applied after a certain amount of idle time
+        Useful to hide f.ex navigation when the gallery is inactive
+
+        @param {HTMLElement|string} elem The Dom node or selector to apply the idle state to
+        @param {Object} styles the CSS styles to apply when in idle mode
+        @param {Object} [from] the CSS styles to apply when in normal
+        @param {Boolean} [hide] set to true if you want to hide it first
+
+        @example addIdleState( this.get('image-nav'), { opacity: 0 });
+        @example addIdleState( '.galleria-image-nav', { top: -200 }, true);
+
+        @returns Instance
+    */
+
+    addIdleState: function( elem, styles, from, hide ) {
+        this._idle.add.apply( this._idle, Utils.array( arguments ) );
+        return this;
+    },
+
+    /**
+        Removes any idle state previously set using addIdleState()
+
+        @param {HTMLElement|string} elem The Dom node or selector to remove the idle state from.
+
+        @returns Instance
+    */
+
+    removeIdleState: function( elem ) {
+        this._idle.remove.apply( this._idle, Utils.array( arguments ) );
+        return this;
+    },
+
+    /**
+        Force Galleria to enter idle mode.
+
+        @returns Instance
+    */
+
+    enterIdleMode: function() {
+        this._idle.hide();
+        return this;
+    },
+
+    /**
+        Force Galleria to exit idle mode.
+
+        @returns Instance
+    */
+
+    exitIdleMode: function() {
+        this._idle.showAll();
+        return this;
+    },
+
+    /**
+        Enter FullScreen mode
+
+        @param {Function} callback the function to be executed when the fullscreen mode is fully applied.
+
+        @returns Instance
+    */
+
+    enterFullscreen: function( callback ) {
+        this._fullscreen.enter.apply( this, Utils.array( arguments ) );
+        return this;
+    },
+
+    /**
+        Exits FullScreen mode
+
+        @param {Function} callback the function to be executed when the fullscreen mode is fully applied.
+
+        @returns Instance
+    */
+
+    exitFullscreen: function( callback ) {
+        this._fullscreen.exit.apply( this, Utils.array( arguments ) );
+        return this;
+    },
+
+    /**
+        Toggle FullScreen mode
+
+        @param {Function} callback the function to be executed when the fullscreen mode is fully applied or removed.
+
+        @returns Instance
+    */
+
+    toggleFullscreen: function( callback ) {
+        this._fullscreen[ this.isFullscreen() ? 'exit' : 'enter'].apply( this, Utils.array( arguments ) );
+        return this;
+    },
+
+    /**
+        Adds a tooltip to any element.
+        You can also call this method with an object as argument with elemID:value pairs to apply tooltips to (see examples)
+
+        @param {HTMLElement} elem The DOM Node to attach the event to
+        @param {string|Function} value The tooltip message. Can also be a function that returns a string.
+
+        @example this.bindTooltip( this.get('thumbnails'), 'My thumbnails');
+        @example this.bindTooltip( this.get('thumbnails'), function() { return 'My thumbs' });
+        @example this.bindTooltip( { image_nav: 'Navigation' });
+
+        @returns Instance
+    */
+
+    bindTooltip: function( elem, value ) {
+        this._tooltip.bind.apply( this._tooltip, Utils.array(arguments) );
+        return this;
+    },
+
+    /**
+        Note: this method is deprecated. Use refreshTooltip() instead.
+
+        Redefine a tooltip.
+        Use this if you want to re-apply a tooltip value to an already bound tooltip element.
+
+        @param {HTMLElement} elem The DOM Node to attach the event to
+        @param {string|Function} value The tooltip message. Can also be a function that returns a string.
+
+        @returns Instance
+    */
+
+    defineTooltip: function( elem, value ) {
+        this._tooltip.define.apply( this._tooltip, Utils.array(arguments) );
+        return this;
+    },
+
+    /**
+        Refresh a tooltip value.
+        Use this if you want to change the tooltip value at runtime, f.ex if you have a play/pause toggle.
+
+        @param {HTMLElement} elem The DOM Node that has a tooltip that should be refreshed
+
+        @returns Instance
+    */
+
+    refreshTooltip: function( elem ) {
+        this._tooltip.show.apply( this._tooltip, Utils.array(arguments) );
+        return this;
+    },
+
+    /**
+        Open a pre-designed lightbox with the currently active image.
+        You can control some visuals using gallery options.
+
+        @returns Instance
+    */
+
+    openLightbox: function() {
+        this._lightbox.show.apply( this._lightbox, Utils.array( arguments ) );
+        return this;
+    },
+
+    /**
+        Close the lightbox.
+
+        @returns Instance
+    */
+
+    closeLightbox: function() {
+        this._lightbox.hide.apply( this._lightbox, Utils.array( arguments ) );
+        return this;
+    },
+
+    /**
+        Check if a variation exists
+
+        @returns {Boolean} If the variation has been applied
+    */
+
+    hasVariation: function( variation ) {
+        return $.inArray( variation, this._options.variation.split(/\s+/) ) > -1;
+    },
+
+    /**
+        Get the currently active image element.
+
+        @returns {HTMLElement} The image element
+    */
+
+    getActiveImage: function() {
+        var active = this._getActive();
+        return active ? active.image : undef;
+    },
+
+    /**
+        Get the currently active thumbnail element.
+
+        @returns {HTMLElement} The thumbnail element
+    */
+
+    getActiveThumb: function() {
+        return this._thumbnails[ this._active ].image || undef;
+    },
+
+    /**
+        Get the mouse position relative to the gallery container
+
+        @param e The mouse event
+
+        @example
+
+var gallery = this;
+$(document).mousemove(function(e) {
+    console.log( gallery.getMousePosition(e).x );
+});
+
+        @returns {Object} Object with x & y of the relative mouse postion
+    */
+
+    getMousePosition : function(e) {
+        return {
+            x: e.pageX - this.$( 'container' ).offset().left,
+            y: e.pageY - this.$( 'container' ).offset().top
+        };
+    },
+
+    /**
+        Adds a panning effect to the image
+
+        @param [img] The optional image element. If not specified it takes the currently active image
+
+        @returns Instance
+    */
+
+    addPan : function( img ) {
+
+        if ( this._options.imageCrop === false ) {
+            return;
+        }
+
+        img = $( img || this.getActiveImage() );
+
+        // define some variables and methods
+        var self   = this,
+            x      = img.width() / 2,
+            y      = img.height() / 2,
+            destX  = parseInt( img.css( 'left' ), 10 ),
+            destY  = parseInt( img.css( 'top' ), 10 ),
+            curX   = destX || 0,
+            curY   = destY || 0,
+            distX  = 0,
+            distY  = 0,
+            active = false,
+            ts     = Utils.timestamp(),
+            cache  = 0,
+            move   = 0,
+
+            // positions the image
+            position = function( dist, cur, pos ) {
+                if ( dist > 0 ) {
+                    move = M.round( M.max( dist * -1, M.min( 0, cur ) ) );
+                    if ( cache !== move ) {
+
+                        cache = move;
+
+                        if ( IE === 8 ) { // scroll is faster for IE
+                            img.parent()[ 'scroll' + pos ]( move * -1 );
+                        } else {
+                            var css = {};
+                            css[ pos.toLowerCase() ] = move;
+                            img.css(css);
+                        }
+                    }
+                }
+            },
+
+            // calculates mouse position after 50ms
+            calculate = function(e) {
+                if (Utils.timestamp() - ts < 50) {
+                    return;
+                }
+                active = true;
+                x = self.getMousePosition(e).x;
+                y = self.getMousePosition(e).y;
+            },
+
+            // the main loop to check
+            loop = function(e) {
+
+                if (!active) {
+                    return;
+                }
+
+                distX = img.width() - self._stageWidth;
+                distY = img.height() - self._stageHeight;
+                destX = x / self._stageWidth * distX * -1;
+                destY = y / self._stageHeight * distY * -1;
+                curX += ( destX - curX ) / self._options.imagePanSmoothness;
+                curY += ( destY - curY ) / self._options.imagePanSmoothness;
+
+                position( distY, curY, 'Top' );
+                position( distX, curX, 'Left' );
+
+            };
+
+        // we need to use scroll in IE8 to speed things up
+        if ( IE === 8 ) {
+
+            img.parent().scrollTop( curY * -1 ).scrollLeft( curX * -1 );
+            img.css({
+                top: 0,
+                left: 0
+            });
+
+        }
+
+        // unbind and bind event
+        this.$( 'stage' ).unbind( 'mousemove', calculate ).bind( 'mousemove', calculate );
+
+        // loop the loop
+        this.addTimer( 'pan' + self._id, loop, 50, true);
+
+        return this;
+    },
+
+    /**
+        Brings the scope into any callback
+
+        @param fn The callback to bring the scope into
+        @param [scope] Optional scope to bring
+
+        @example $('#fullscreen').click( this.proxy(function() { this.enterFullscreen(); }) )
+
+        @returns {Function} Return the callback with the gallery scope
+    */
+
+    proxy : function( fn, scope ) {
+        if ( typeof fn !== 'function' ) {
+            return F;
+        }
+        scope = scope || this;
+        return function() {
+            return fn.apply( scope, Utils.array( arguments ) );
+        };
+    },
+
+    /**
+        Removes the panning effect set by addPan()
+
+        @returns Instance
+    */
+
+    removePan: function() {
+
+        // todo: doublecheck IE8
+
+        this.$( 'stage' ).unbind( 'mousemove' );
+
+        this.clearTimer( 'pan' + this._id );
+
+        return this;
+    },
+
+    /**
+        Adds an element to the Galleria DOM array.
+        When you add an element here, you can access it using element ID in many API calls
+
+        @param {string} id The element ID you wish to use. You can add many elements by adding more arguments.
+
+        @example addElement('mybutton');
+        @example addElement('mybutton','mylink');
+
+        @returns Instance
+    */
+
+    addElement : function( id ) {
+
+        var dom = this._dom;
+
+        $.each( Utils.array(arguments), function( i, blueprint ) {
+           dom[ blueprint ] = Utils.create( 'galleria-' + blueprint );
+        });
+
+        return this;
+    },
+
+    /**
+        Attach keyboard events to Galleria
+
+        @param {Object} map The map object of events.
+        Possible keys are 'UP', 'DOWN', 'LEFT', 'RIGHT', 'RETURN', 'ESCAPE', 'BACKSPACE', and 'SPACE'.
+
+        @example
+
+this.attachKeyboard({
+    right: this.next,
+    left: this.prev,
+    up: function() {
+        console.log( 'up key pressed' )
+    }
+});
+
+        @returns Instance
+    */
+
+    attachKeyboard : function( map ) {
+        this._keyboard.attach.apply( this._keyboard, Utils.array( arguments ) );
+        return this;
+    },
+
+    /**
+        Detach all keyboard events to Galleria
+
+        @returns Instance
+    */
+
+    detachKeyboard : function() {
+        this._keyboard.detach.apply( this._keyboard, Utils.array( arguments ) );
+        return this;
+    },
+
+    /**
+        Fast helper for appending galleria elements that you added using addElement()
+
+        @param {string} parentID The parent element ID where the element will be appended
+        @param {string} childID the element ID that should be appended
+
+        @example this.addElement('myElement');
+        this.appendChild( 'info', 'myElement' );
+
+        @returns Instance
+    */
+
+    appendChild : function( parentID, childID ) {
+        this.$( parentID ).append( this.get( childID ) || childID );
+        return this;
+    },
+
+    /**
+        Fast helper for prepending galleria elements that you added using addElement()
+
+        @param {string} parentID The parent element ID where the element will be prepended
+        @param {string} childID the element ID that should be prepended
+
+        @example
+
+this.addElement('myElement');
+this.prependChild( 'info', 'myElement' );
+
+        @returns Instance
+    */
+
+    prependChild : function( parentID, childID ) {
+        this.$( parentID ).prepend( this.get( childID ) || childID );
+        return this;
+    },
+
+    /**
+        Remove an element by blueprint
+
+        @param {string} elemID The element to be removed.
+        You can remove multiple elements by adding arguments.
+
+        @returns Instance
+    */
+
+    remove : function( elemID ) {
+        this.$( Utils.array( arguments ).join(',') ).remove();
+        return this;
+    },
+
+    // a fast helper for building dom structures
+    // leave this out of the API for now
+
+    append : function( data ) {
+        var i, j;
+        for( i in data ) {
+            if ( data.hasOwnProperty( i ) ) {
+                if ( data[i].constructor === Array ) {
+                    for( j = 0; data[i][j]; j++ ) {
+                        this.appendChild( i, data[i][j] );
+                    }
+                } else {
+                    this.appendChild( i, data[i] );
+                }
+            }
+        }
+        return this;
+    },
+
+    // an internal helper for scaling according to options
+    _scaleImage : function( image, options ) {
+
+        image = image || this._controls.getActive();
+
+        // janpub (JH) fix:
+        // image might be unselected yet
+        // e.g. when external logics rescales the gallery on window resize events
+        if( !image ) {
+            return;
+        }
+
+        var complete,
+
+            scaleLayer = function( img ) {
+                $( img.container ).children(':first').css({
+                    top: M.max(0, Utils.parseValue( img.image.style.top )),
+                    left: M.max(0, Utils.parseValue( img.image.style.left )),
+                    width: Utils.parseValue( img.image.width ),
+                    height: Utils.parseValue( img.image.height )
+                });
+            };
+
+        options = $.extend({
+            width:       this._stageWidth,
+            height:      this._stageHeight,
+            crop:        this._options.imageCrop,
+            max:         this._options.maxScaleRatio,
+            min:         this._options.minScaleRatio,
+            margin:      this._options.imageMargin,
+            position:    this._options.imagePosition,
+            iframelimit: this._options.maxVideoSize
+        }, options );
+
+        if ( this._options.layerFollow && this._options.imageCrop !== true ) {
+
+            if ( typeof options.complete == 'function' ) {
+                complete = options.complete;
+                options.complete = function() {
+                    complete.call( image, image );
+                    scaleLayer( image );
+                };
+            } else {
+                options.complete = scaleLayer;
+            }
+
+        } else {
+            $( image.container ).children(':first').css({ top: 0, left: 0 });
+        }
+
+        image.scale( options );
+        return this;
+    },
+
+    /**
+        Updates the carousel,
+        useful if you resize the gallery and want to re-check if the carousel nav is needed.
+
+        @returns Instance
+    */
+
+    updateCarousel : function() {
+        this._carousel.update();
+        return this;
+    },
+
+    /**
+        Resize the entire gallery container
+
+        @param {Object} [measures] Optional object with width/height specified
+        @param {Function} [complete] The callback to be called when the scaling is complete
+
+        @returns Instance
+    */
+
+    resize : function( measures, complete ) {
+
+        if ( typeof measures == 'function' ) {
+            complete = measures;
+            measures = undef;
+        }
+
+        measures = $.extend( { width:0, height:0 }, measures );
+
+        var self = this,
+            $container = this.$( 'container' );
+
+        $.each( measures, function( m, val ) {
+            if ( !val ) {
+                $container[ m ]( 'auto' );
+                measures[ m ] = self._getWH()[ m ];
+            }
+        });
+
+        $.each( measures, function( m, val ) {
+            $container[ m ]( val );
+        });
+
+        return this.rescale( complete );
+
+    },
+
+    /**
+        Rescales the gallery
+
+        @param {number} width The target width
+        @param {number} height The target height
+        @param {Function} complete The callback to be called when the scaling is complete
+
+        @returns Instance
+    */
+
+    rescale : function( width, height, complete ) {
+
+        var self = this;
+
+        // allow rescale(fn)
+        if ( typeof width === 'function' ) {
+            complete = width;
+            width = undef;
+        }
+
+        var scale = function() {
+
+            // set stagewidth
+            self._stageWidth = width || self.$( 'stage' ).width();
+            self._stageHeight = height || self.$( 'stage' ).height();
+
+            if ( self._options.swipe ) {
+                $.each( self._controls.slides, function(i, img) {
+                    self._scaleImage( img );
+                    $( img.container ).css('left', self._stageWidth * i);
+                });
+                self.$('images').css('width', self._stageWidth * self.getDataLength());
+            } else {
+                // scale the active image
+                self._scaleImage();
+            }
+
+            if ( self._options.carousel ) {
+                self.updateCarousel();
+            }
+
+            self._controls.frames[ self._controls.active ].scale({
+                width: self._stageWidth,
+                height: self._stageHeight,
+                iframelimit: self._options.maxVideoSize
+            });
+
+            self.trigger( Galleria.RESCALE );
+
+            if ( typeof complete === 'function' ) {
+                complete.call( self );
+            }
+        };
+
+        scale.call( self );
+
+        return this;
+    },
+
+    /**
+        Refreshes the gallery.
+        Useful if you change image options at runtime and want to apply the changes to the active image.
+
+        @returns Instance
+    */
+
+    refreshImage : function() {
+        this._scaleImage();
+        if ( this._options.imagePan ) {
+            this.addPan();
+        }
+        return this;
+    },
+
+    /**
+        Shows an image by index
+
+        @param {number|boolean} index The index to show
+        @param {Boolean} rewind A boolean that should be true if you want the transition to go back
+
+        @returns Instance
+    */
+
+    show : function( index, rewind, _history ) {
+
+        var swipe = this._options.swipe;
+
+        // do nothing queue is long || index is false || queue is false and transition is in progress
+        if ( !swipe &&
+            ( this._queue.length > 3 || index === false || ( !this._options.queue && this._queue.stalled ) ) ) {
+            return;
+        }
+
+        index = M.max( 0, M.min( parseInt( index, 10 ), this.getDataLength() - 1 ) );
+
+        rewind = typeof rewind !== 'undefined' ? !!rewind : index < this.getIndex();
+
+        _history = _history || false;
+
+        // do the history thing and return
+        if ( !_history && Galleria.History ) {
+            Galleria.History.set( index.toString() );
+            return;
+        }
+
+        if ( this.finger && index !== this._active ) {
+            this.finger.to = -( index*this.finger.width );
+            this.finger.index = index;
+        }
+
+        this._active = index;
+
+        // we do things a bit simpler in swipe:
+        if ( swipe ) {
+
+            var data = this.getData(index),
+                self = this;
+            if ( !data ) {
+                return;
+            }
+
+            var src = this.isFullscreen() && data.big ? data.big : ( data.image || data.iframe ),
+                image = this._controls.slides[index],
+                cached = image.isCached( src ),
+                thumb = this._thumbnails[ index ];
+
+            var evObj = {
+                cached: cached,
+                index: index,
+                rewind: rewind,
+                imageTarget: image.image,
+                thumbTarget: thumb.image,
+                galleriaData: data
+            };
+
+            this.trigger($.extend(evObj, {
+                type: Galleria.LOADSTART
+            }));
+
+            $( self._thumbnails[ index ].container )
+                .addClass( 'active' )
+                .siblings( '.active' )
+                .removeClass( 'active' );
+
+            self.$('container').removeClass( 'videoplay' );
+
+            var complete = function() {
+
+                self._layers[index].innerHTML = self.getData().layer || '';
+
+                self.trigger($.extend(evObj, {
+                    type: Galleria.LOADFINISH
+                }));
+                self._playCheck();
+            };
+
+            window.setTimeout(function() {
+
+                // load if not ready
+                if ( !image.ready ) {
+                    if ( data.iframe && !data.image ) {
+                        image.isIframe = true;
+                    }
+                    image.load(src, function(image) {
+                        self._scaleImage(image, complete).trigger($.extend(evObj, {
+                            type: Galleria.IMAGE
+                        }));
+                        complete();
+                    });
+                } else {
+                    self.trigger($.extend(evObj, {
+                        type: Galleria.IMAGE
+                    }));
+                    complete();
+                }
+            },800);
+
+        } else {
+            protoArray.push.call( this._queue, {
+                index : index,
+                rewind : rewind
+            });
+            if ( !this._queue.stalled ) {
+                this._show();
+            }
+        }
+
+        return this;
+    },
+
+    // the internal _show method does the actual showing
+    _show : function() {
+
+        // shortcuts
+        var self = this,
+            queue = this._queue[ 0 ],
+            data = this.getData( queue.index );
+
+        if ( !data ) {
+            return;
+        }
+
+        var src = this.isFullscreen() && data.big ? data.big : ( data.image || data.iframe ),
+            active = this._controls.getActive(),
+            next = this._controls.getNext(),
+            cached = next.isCached( src ),
+            thumb = this._thumbnails[ queue.index ],
+            mousetrigger = function() {
+                $( next.image ).trigger( 'mouseup' );
+            };
+
+        self.$('container').toggleClass('iframe', !!data.isIframe).removeClass( 'videoplay' );
+
+        // to be fired when loading & transition is complete:
+        var complete = (function( data, next, active, queue, thumb ) {
+
+            return function() {
+
+                var win;
+
+                _transitions.active = false;
+
+                // optimize quality
+                Utils.toggleQuality( next.image, self._options.imageQuality );
+
+                // remove old layer
+                self._layers[ self._controls.active ].innerHTML = '';
+
+                // swap
+                $( active.container ).css({
+                    zIndex: 0,
+                    opacity: 0
+                }).show();
+
+                $( active.container ).find( 'iframe, .galleria-videoicon' ).remove();
+                $( self._controls.frames[ self._controls.active ].container ).hide();
+
+                $( next.container ).css({
+                    zIndex: 1,
+                    left: 0,
+                    top: 0
+                }).show();
+
+                self._controls.swap();
+
+                // add pan according to option
+                if ( self._options.imagePan ) {
+                    self.addPan( next.image );
+                }
+
+                // make the image clickable
+                // order of precedence: iframe, link, lightbox, clicknext
+                if ( ( data.iframe && data.image ) || data.link || self._options.lightbox || self._options.clicknext ) {
+
+                    $( next.image ).css({
+                        cursor: 'pointer'
+                    }).bind( 'mouseup', function( e ) {
+
+                        // non-left click
+                        if ( typeof e.which == 'number' && e.which > 1 ) {
+                            return;
+                        }
+
+                        // iframe / video
+                        if ( data.iframe ) {
+
+                            if ( self.isPlaying() ) {
+                                self.pause();
+                            }
+                            var frame = self._controls.frames[ self._controls.active ],
+                                w = self._stageWidth,
+                                h = self._stageHeight;
+
+                            $( frame.container ).css({
+                                width: w,
+                                height: h,
+                                opacity: 0
+                            }).show().animate({
+                                opacity: 1
+                            }, 200);
+
+                            window.setTimeout(function() {
+                                frame.load( data.iframe + ( data.video ? '&autoplay=1' : '' ), {
+                                    width: w,
+                                    height: h
+                                }, function( frame ) {
+                                    self.$( 'container' ).addClass( 'videoplay' );
+                                    frame.scale({
+                                        width: self._stageWidth,
+                                        height: self._stageHeight,
+                                        iframelimit: data.video ? self._options.maxVideoSize : undef
+                                    });
+                                });
+                            }, 100);
+
+                            return;
+                        }
+
+                        // clicknext
+                        if ( self._options.clicknext && !Galleria.TOUCH ) {
+                            if ( self._options.pauseOnInteraction ) {
+                                self.pause();
+                            }
+                            self.next();
+                            return;
+                        }
+
+                        // popup link
+                        if ( data.link ) {
+                            if ( self._options.popupLinks ) {
+                                win = window.open( data.link, '_blank' );
+                            } else {
+                                window.location.href = data.link;
+                            }
+                            return;
+                        }
+
+                        if ( self._options.lightbox ) {
+                            self.openLightbox();
+                        }
+
+                    });
+                }
+
+                // check if we are playing
+                self._playCheck();
+
+                // trigger IMAGE event
+                self.trigger({
+                    type: Galleria.IMAGE,
+                    index: queue.index,
+                    imageTarget: next.image,
+                    thumbTarget: thumb.image,
+                    galleriaData: data
+                });
+
+                // remove the queued image
+                protoArray.shift.call( self._queue );
+
+                // remove stalled
+                self._queue.stalled = false;
+
+                // if we still have images in the queue, show it
+                if ( self._queue.length ) {
+                    self._show();
+                }
+
+            };
+        }( data, next, active, queue, thumb ));
+
+        // let the carousel follow
+        if ( this._options.carousel && this._options.carouselFollow ) {
+            this._carousel.follow( queue.index );
+        }
+
+        // preload images
+        if ( this._options.preload ) {
+
+            var p, i,
+                n = this.getNext(),
+                ndata;
+
+            try {
+                for ( i = this._options.preload; i > 0; i-- ) {
+                    p = new Galleria.Picture();
+                    ndata = self.getData( n );
+                    p.preload( this.isFullscreen() && ndata.big ? ndata.big : ndata.image );
+                    n = self.getNext( n );
+                }
+            } catch(e) {}
+        }
+
+        // show the next image, just in case
+        Utils.show( next.container );
+
+        next.isIframe = data.iframe && !data.image;
+
+        // add active classes
+        $( self._thumbnails[ queue.index ].container )
+            .addClass( 'active' )
+            .siblings( '.active' )
+            .removeClass( 'active' );
+
+        // trigger the LOADSTART event
+        self.trigger( {
+            type: Galleria.LOADSTART,
+            cached: cached,
+            index: queue.index,
+            rewind: queue.rewind,
+            imageTarget: next.image,
+            thumbTarget: thumb.image,
+            galleriaData: data
+        });
+
+        // stall the queue
+        self._queue.stalled = true;
+
+        // begin loading the next image
+        next.load( src, function( next ) {
+
+            // add layer HTML
+            var layer = $( self._layers[ 1-self._controls.active ] ).html( data.layer || '' ).hide();
+
+            self._scaleImage( next, {
+
+                complete: function( next ) {
+
+                    // toggle low quality for IE
+                    if ( 'image' in active ) {
+                        Utils.toggleQuality( active.image, false );
+                    }
+                    Utils.toggleQuality( next.image, false );
+
+                    // remove the image panning, if applied
+                    // TODO: rethink if this is necessary
+                    self.removePan();
+
+                    // set the captions and counter
+                    self.setInfo( queue.index );
+                    self.setCounter( queue.index );
+
+                    // show the layer now
+                    if ( data.layer ) {
+                        layer.show();
+                        // inherit click events set on image
+                        if ( ( data.iframe && data.image ) || data.link || self._options.lightbox || self._options.clicknext ) {
+                            layer.css( 'cursor', 'pointer' ).unbind( 'mouseup' ).mouseup( mousetrigger );
+                        }
+                    }
+
+                    // add play icon
+                    if( data.video && data.image ) {
+                        _playIcon( next.container );
+                    }
+
+                    var transition = self._options.transition;
+
+                    // can JavaScript loop through objects in order? yes.
+                    $.each({
+                        initial: active.image === null,
+                        touch: Galleria.TOUCH,
+                        fullscreen: self.isFullscreen()
+                    }, function( type, arg ) {
+                        if ( arg && self._options[ type + 'Transition' ] !== undef ) {
+                            transition = self._options[ type + 'Transition' ];
+                            return false;
+                        }
+                    });
+
+                    // validate the transition
+                    if ( transition in _transitions.effects === false ) {
+                        complete();
+                    } else {
+                        var params = {
+                            prev: active.container,
+                            next: next.container,
+                            rewind: queue.rewind,
+                            speed: self._options.transitionSpeed || 400
+                        };
+
+                        _transitions.active = true;
+
+                        // call the transition function and send some stuff
+                        _transitions.init.call( self, transition, params, complete );
+
+                    }
+
+                    // trigger the LOADFINISH event
+                    self.trigger({
+                        type: Galleria.LOADFINISH,
+                        cached: cached,
+                        index: queue.index,
+                        rewind: queue.rewind,
+                        imageTarget: next.image,
+                        thumbTarget: self._thumbnails[ queue.index ].image,
+                        galleriaData: self.getData( queue.index )
+                    });
+                }
+            });
+        });
+    },
+
+    /**
+        Gets the next index
+
+        @param {number} [base] Optional starting point
+
+        @returns {number} the next index, or the first if you are at the first (looping)
+    */
+
+    getNext : function( base ) {
+        base = typeof base === 'number' ? base : this.getIndex();
+        return base === this.getDataLength() - 1 ? 0 : base + 1;
+    },
+
+    /**
+        Gets the previous index
+
+        @param {number} [base] Optional starting point
+
+        @returns {number} the previous index, or the last if you are at the first (looping)
+    */
+
+    getPrev : function( base ) {
+        base = typeof base === 'number' ? base : this.getIndex();
+        return base === 0 ? this.getDataLength() - 1 : base - 1;
+    },
+
+    /**
+        Shows the next image in line
+
+        @returns Instance
+    */
+
+    next : function() {
+        if ( this.getDataLength() > 1 ) {
+            this.show( this.getNext(), false );
+        }
+        return this;
+    },
+
+    /**
+        Shows the previous image in line
+
+        @returns Instance
+    */
+
+    prev : function() {
+        if ( this.getDataLength() > 1 ) {
+            this.show( this.getPrev(), true );
+        }
+        return this;
+    },
+
+    /**
+        Retrieve a DOM element by element ID
+
+        @param {string} elemId The delement ID to fetch
+
+        @returns {HTMLElement} The elements DOM node or null if not found.
+    */
+
+    get : function( elemId ) {
+        return elemId in this._dom ? this._dom[ elemId ] : null;
+    },
+
+    /**
+        Retrieve a data object
+
+        @param {number} index The data index to retrieve.
+        If no index specified it will take the currently active image
+
+        @returns {Object} The data object
+    */
+
+    getData : function( index ) {
+        return index in this._data ?
+            this._data[ index ] : this._data[ this._active ];
+    },
+
+    /**
+        Retrieve the number of data items
+
+        @returns {number} The data length
+    */
+    getDataLength : function() {
+        return this._data.length;
+    },
+
+    /**
+        Retrieve the currently active index
+
+        @returns {number|boolean} The active index or false if none found
+    */
+
+    getIndex : function() {
+        return typeof this._active === 'number' ? this._active : false;
+    },
+
+    /**
+        Retrieve the stage height
+
+        @returns {number} The stage height
+    */
+
+    getStageHeight : function() {
+        return this._stageHeight;
+    },
+
+    /**
+        Retrieve the stage width
+
+        @returns {number} The stage width
+    */
+
+    getStageWidth : function() {
+        return this._stageWidth;
+    },
+
+    /**
+        Retrieve the option
+
+        @param {string} key The option key to retrieve. If no key specified it will return all options in an object.
+
+        @returns option or options
+    */
+
+    getOptions : function( key ) {
+        return typeof key === 'undefined' ? this._options : this._options[ key ];
+    },
+
+    /**
+        Set options to the instance.
+        You can set options using a key & value argument or a single object argument (see examples)
+
+        @param {string} key The option key
+        @param {string} value the the options value
+
+        @example setOptions( 'autoplay', true )
+        @example setOptions({ autoplay: true });
+
+        @returns Instance
+    */
+
+    setOptions : function( key, value ) {
+        if ( typeof key === 'object' ) {
+            $.extend( this._options, key );
+        } else {
+            this._options[ key ] = value;
+        }
+        return this;
+    },
+
+    /**
+        Starts playing the slideshow
+
+        @param {number} delay Sets the slideshow interval in milliseconds.
+        If you set it once, you can just call play() and get the same interval the next time.
+
+        @returns Instance
+    */
+
+    play : function( delay ) {
+
+        this._playing = true;
+
+        this._playtime = delay || this._playtime;
+
+        this._playCheck();
+
+        this.trigger( Galleria.PLAY );
+
+        return this;
+    },
+
+    /**
+        Stops the slideshow if currently playing
+
+        @returns Instance
+    */
+
+    pause : function() {
+
+        this._playing = false;
+
+        this.trigger( Galleria.PAUSE );
+
+        return this;
+    },
+
+    /**
+        Toggle between play and pause events.
+
+        @param {number} delay Sets the slideshow interval in milliseconds.
+
+        @returns Instance
+    */
+
+    playToggle : function( delay ) {
+        return ( this._playing ) ? this.pause() : this.play( delay );
+    },
+
+    /**
+        Checks if the gallery is currently playing
+
+        @returns {Boolean}
+    */
+
+    isPlaying : function() {
+        return this._playing;
+    },
+
+    /**
+        Checks if the gallery is currently in fullscreen mode
+
+        @returns {Boolean}
+    */
+
+    isFullscreen : function() {
+        return this._fullscreen.active;
+    },
+
+    _playCheck : function() {
+        var self = this,
+            played = 0,
+            interval = 20,
+            now = Utils.timestamp(),
+            timer_id = 'play' + this._id;
+
+        if ( this._playing ) {
+
+            this.clearTimer( timer_id );
+
+            var fn = function() {
+
+                played = Utils.timestamp() - now;
+                if ( played >= self._playtime && self._playing ) {
+                    self.clearTimer( timer_id );
+                    self.next();
+                    return;
+                }
+                if ( self._playing ) {
+
+                    // trigger the PROGRESS event
+                    self.trigger({
+                        type:         Galleria.PROGRESS,
+                        percent:      M.ceil( played / self._playtime * 100 ),
+                        seconds:      M.floor( played / 1000 ),
+                        milliseconds: played
+                    });
+
+                    self.addTimer( timer_id, fn, interval );
+                }
+            };
+            self.addTimer( timer_id, fn, interval );
+        }
+    },
+
+    /**
+        Modify the slideshow delay
+
+        @param {number} delay the number of milliseconds between slides,
+
+        @returns Instance
+    */
+
+    setPlaytime: function( delay ) {
+        this._playtime = delay;
+        return this;
+    },
+
+    setIndex: function( val ) {
+        this._active = val;
+        return this;
+    },
+
+    /**
+        Manually modify the counter
+
+        @param {number} [index] Optional data index to fectch,
+        if no index found it assumes the currently active index
+
+        @returns Instance
+    */
+
+    setCounter: function( index ) {
+
+        if ( typeof index === 'number' ) {
+            index++;
+        } else if ( typeof index === 'undefined' ) {
+            index = this.getIndex()+1;
+        }
+
+        this.get( 'current' ).innerHTML = index;
+
+        if ( IE ) { // weird IE bug
+
+            var count = this.$( 'counter' ),
+                opacity = count.css( 'opacity' );
+
+            if ( parseInt( opacity, 10 ) === 1) {
+                Utils.removeAlpha( count[0] );
+            } else {
+                this.$( 'counter' ).css( 'opacity', opacity );
+            }
+
+        }
+
+        return this;
+    },
+
+    /**
+        Manually set captions
+
+        @param {number} [index] Optional data index to fectch and apply as caption,
+        if no index found it assumes the currently active index
+
+        @returns Instance
+    */
+
+    setInfo : function( index ) {
+
+        var self = this,
+            data = this.getData( index );
+
+        $.each( ['title','description'], function( i, type ) {
+
+            var elem = self.$( 'info-' + type );
+
+            if ( !!data[type] ) {
+                elem[ data[ type ].length ? 'show' : 'hide' ]().html( data[ type ] );
+            } else {
+               elem.empty().hide();
+            }
+        });
+
+        return this;
+    },
+
+    /**
+        Checks if the data contains any captions
+
+        @param {number} [index] Optional data index to fectch,
+        if no index found it assumes the currently active index.
+
+        @returns {boolean}
+    */
+
+    hasInfo : function( index ) {
+
+        var check = 'title description'.split(' '),
+            i;
+
+        for ( i = 0; check[i]; i++ ) {
+            if ( !!this.getData( index )[ check[i] ] ) {
+                return true;
+            }
+        }
+        return false;
+
+    },
+
+    jQuery : function( str ) {
+
+        var self = this,
+            ret = [];
+
+        $.each( str.split(','), function( i, elemId ) {
+            elemId = $.trim( elemId );
+
+            if ( self.get( elemId ) ) {
+                ret.push( elemId );
+            }
+        });
+
+        var jQ = $( self.get( ret.shift() ) );
+
+        $.each( ret, function( i, elemId ) {
+            jQ = jQ.add( self.get( elemId ) );
+        });
+
+        return jQ;
+
+    },
+
+    /**
+        Converts element IDs into a jQuery collection
+        You can call for multiple IDs separated with commas.
+
+        @param {string} str One or more element IDs (comma-separated)
+
+        @returns jQuery
+
+        @example this.$('info,container').hide();
+    */
+
+    $ : function( str ) {
+        return this.jQuery.apply( this, Utils.array( arguments ) );
+    }
+
+};
+
+// End of Galleria prototype
+
+// Add events as static variables
+$.each( _events, function( i, ev ) {
+
+    // legacy events
+    var type = /_/.test( ev ) ? ev.replace( /_/g, '' ) : ev;
+
+    Galleria[ ev.toUpperCase() ] = 'galleria.'+type;
+
+} );
+
+$.extend( Galleria, {
+
+    // Browser helpers
+    IE9:     IE === 9,
+    IE8:     IE === 8,
+    IE7:     IE === 7,
+    IE6:     IE === 6,
+    IE:      IE,
+    WEBKIT:  /webkit/.test( NAV ),
+    CHROME:  /chrome/.test( NAV ),
+    SAFARI:  /safari/.test( NAV ) && !(/chrome/.test( NAV )),
+    QUIRK:   ( IE && doc.compatMode && doc.compatMode === "BackCompat" ),
+    MAC:     /mac/.test( navigator.platform.toLowerCase() ),
+    OPERA:   !!window.opera,
+    IPHONE:  /iphone/.test( NAV ),
+    IPAD:    /ipad/.test( NAV ),
+    ANDROID: /android/.test( NAV ),
+    TOUCH:   ('ontouchstart' in doc)
+
+});
+
+// Galleria static methods
+
+/**
+    Adds a theme that you can use for your Gallery
+
+    @param {Object} theme Object that should contain all your theme settings.
+    <ul>
+        <li>name - name of the theme</li>
+        <li>author - name of the author</li>
+        <li>css - css file name (not path)</li>
+        <li>defaults - default options to apply, including theme-specific options</li>
+        <li>init - the init function</li>
+    </ul>
+
+    @returns {Object} theme
+*/
+
+Galleria.addTheme = function( theme ) {
+
+    // make sure we have a name
+    if ( !theme.name ) {
+        Galleria.raise('No theme name specified');
+    }
+
+    if ( typeof theme.defaults !== 'object' ) {
+        theme.defaults = {};
+    } else {
+        theme.defaults = _legacyOptions( theme.defaults );
+    }
+
+    var css = false,
+        reg;
+
+    if ( typeof theme.css === 'string' ) {
+
+        // look for manually added CSS
+        $('link').each(function( i, link ) {
+            reg = new RegExp( theme.css );
+            if ( reg.test( link.href ) ) {
+
+                // we found the css
+                css = true;
+
+                // the themeload trigger
+                _themeLoad( theme );
+
+                return false;
+            }
+        });
+
+        // else look for the absolute path and load the CSS dynamic
+        if ( !css ) {
+
+            $(function() {
+
+                $('script').each(function( i, script ) {
+                    // look for the theme script
+                    reg = new RegExp( 'galleria\\.' + theme.name.toLowerCase() + '\\.' );
+                    if( reg.test( script.src )) {
+
+                        // we have a match
+                        css = script.src.replace(/[^\/]*$/, '') + theme.css;
+
+                        window.setTimeout(function() {
+                            Utils.loadCSS( css, 'galleria-theme', function() {
+
+                                // the themeload trigger
+                                _themeLoad( theme );
+
+                            });
+                        }, 1);
+                    }
+                });
+                if ( !css ) {
+                    Galleria.raise('No theme CSS loaded');
+                }
+            });
+        }
+
+    } else {
+
+        // pass
+        _themeLoad( theme );
+    }
+    return theme;
+};
+
+/**
+    loadTheme loads a theme js file and attaches a load event to Galleria
+
+    @param {string} src The relative path to the theme source file
+
+    @param {Object} [options] Optional options you want to apply
+
+    @returns Galleria
+*/
+
+Galleria.loadTheme = function( src, options ) {
+
+    // Don't load if theme is already loaded
+    if( $('script').filter(function() { return $(this).attr('src') == src; }).length ) {
+        return;
+    }
+
+    var loaded = false,
+        err;
+
+    // start listening for the timeout onload
+    $( window ).load( function() {
+        if ( !loaded ) {
+            // give it another 20 seconds
+            err = window.setTimeout(function() {
+                if ( !loaded && !Galleria.theme ) {
+                    Galleria.raise( "Galleria had problems loading theme at " + src + ". Please check theme path or load manually.", true );
+                }
+            }, 20000);
+        }
+    });
+
+    // first clear the current theme, if exists
+    Galleria.unloadTheme();
+
+    // load the theme
+    Utils.loadScript( src, function() {
+        loaded = true;
+        window.clearTimeout( err );
+    });
+
+    return Galleria;
+};
+
+/**
+    unloadTheme unloads the Galleria theme and prepares for a new theme
+
+    @returns Galleria
+*/
+
+Galleria.unloadTheme = function() {
+
+    if ( typeof Galleria.theme == 'object' ) {
+
+        $('script').each(function( i, script ) {
+
+            if( new RegExp( 'galleria\\.' + Galleria.theme.name + '\\.' ).test( script.src ) ) {
+                $( script ).remove();
+            }
+        });
+
+        Galleria.theme = undef;
+    }
+
+    return Galleria;
+};
+
+/**
+    Retrieves a Galleria instance.
+
+    @param {number} [index] Optional index to retrieve.
+    If no index is supplied, the method will return all instances in an array.
+
+    @returns Instance or Array of instances
+*/
+
+Galleria.get = function( index ) {
+    if ( !!_instances[ index ] ) {
+        return _instances[ index ];
+    } else if ( typeof index !== 'number' ) {
+        return _instances;
+    } else {
+        Galleria.raise('Gallery index ' + index + ' not found');
+    }
+};
+
+/**
+
+    Configure Galleria options via a static function.
+    The options will be applied to all instances
+
+    @param {string|object} key The options to apply or a key
+
+    @param [value] If key is a string, this is the value
+
+    @returns Galleria
+
+*/
+
+Galleria.configure = function( key, value ) {
+
+    var opts = {};
+
+    if( typeof key == 'string' && value ) {
+        opts[key] = value;
+        key = opts;
+    } else {
+        $.extend( opts, key );
+    }
+
+    Galleria.configure.options = opts;
+
+    $.each( Galleria.get(), function(i, instance) {
+        instance.setOptions( opts );
+    });
+
+    return Galleria;
+};
+
+Galleria.configure.options = {};
+
+/**
+
+    Bind a Galleria event to the gallery
+
+    @param {string} type A string representing the galleria event
+
+    @param {function} callback The function that should run when the event is triggered
+
+    @returns Galleria
+
+*/
+
+Galleria.on = function( type, callback ) {
+    if ( !type ) {
+        return;
+    }
+
+    callback = callback || F;
+
+    // hash the bind
+    var hash = type + callback.toString().replace(/\s/g,'') + Utils.timestamp();
+
+    // for existing instances
+    $.each( Galleria.get(), function(i, instance) {
+        instance._binds.push( hash );
+        instance.bind( type, callback );
+    });
+
+    // for future instances
+    Galleria.on.binds.push({
+        type: type,
+        callback: callback,
+        hash: hash
+    });
+
+    return Galleria;
+};
+
+Galleria.on.binds = [];
+
+/**
+
+    Run Galleria
+    Alias for $(selector).galleria(options)
+
+    @param {string} selector A selector of element(s) to intialize galleria to
+
+    @param {object} options The options to apply
+
+    @returns Galleria
+
+*/
+
+Galleria.run = function( selector, options ) {
+    if ( $.isFunction( options ) ) {
+        options = { extend: options };
+    }
+    $( selector || '#galleria' ).galleria( options );
+    return Galleria;
+};
+
+/**
+    Creates a transition to be used in your gallery
+
+    @param {string} name The name of the transition that you will use as an option
+
+    @param {Function} fn The function to be executed in the transition.
+    The function contains two arguments, params and complete.
+    Use the params Object to integrate the transition, and then call complete when you are done.
+
+    @returns Galleria
+
+*/
+
+Galleria.addTransition = function( name, fn ) {
+    _transitions.effects[name] = fn;
+    return Galleria;
+};
+
+/**
+    The Galleria utilites
+*/
+
+Galleria.utils = Utils;
+
+/**
+    A helper metod for cross-browser logging.
+    It uses the console log if available otherwise it falls back to alert
+
+    @example Galleria.log("hello", document.body, [1,2,3]);
+*/
+
+Galleria.log = function() {
+    var args = Utils.array( arguments );
+    if( 'console' in window && 'log' in window.console ) {
+        try {
+            return window.console.log.apply( window.console, args );
+        } catch( e ) {
+            $.each( args, function() {
+                window.console.log(this);
+            });
+        }
+    } else {
+        return window.alert( args.join('<br>') );
+    }
+};
+
+/**
+    A ready method for adding callbacks when a gallery is ready
+    Each method is call before the extend option for every instance
+
+    @param {function} callback The function to call
+
+    @returns Galleria
+*/
+
+Galleria.ready = function( fn ) {
+    if ( typeof fn != 'function' ) {
+        return Galleria;
+    }
+    $.each( _galleries, function( i, gallery ) {
+        fn.call( gallery, gallery._options );
+    });
+    Galleria.ready.callbacks.push( fn );
+    return Galleria;
+};
+
+Galleria.ready.callbacks = [];
+
+/**
+    Method for raising errors
+
+    @param {string} msg The message to throw
+
+    @param {boolean} [fatal] Set this to true to override debug settings and display a fatal error
+*/
+
+Galleria.raise = function( msg, fatal ) {
+
+    var type = fatal ? 'Fatal error' : 'Error',
+
+        css = {
+            color: '#fff',
+            position: 'absolute',
+            top: 0,
+            left: 0,
+            zIndex: 100000
+        },
+
+        echo = function( msg ) {
+
+            var html = '<div style="padding:4px;margin:0 0 2px;background:#' +
+                ( fatal ? '811' : '222' ) + ';">' +
+                ( fatal ? '<strong>' + type + ': </strong>' : '' ) +
+                msg + '</div>';
+
+            $.each( _instances, function() {
+
+                var cont = this.$( 'errors' ),
+                    target = this.$( 'target' );
+
+                if ( !cont.length ) {
+
+                    target.css( 'position', 'relative' );
+
+                    cont = this.addElement( 'errors' ).appendChild( 'target', 'errors' ).$( 'errors' ).css(css);
+                }
+                cont.append( html );
+
+            });
+
+            if ( !_instances.length ) {
+                $('<div>').css( $.extend( css, { position: 'fixed' } ) ).append( html ).appendTo( DOM().body );
+            }
+        };
+
+    // if debug is on, display errors and throw exception if fatal
+    if ( DEBUG ) {
+        echo( msg );
+        if ( fatal ) {
+            throw new Error(type + ': ' + msg);
+        }
+
+    // else just echo a silent generic error if fatal
+    } else if ( fatal ) {
+        if ( _hasError ) {
+            return;
+        }
+        _hasError = true;
+        fatal = false;
+        echo( 'Gallery could not load.' );
+    }
+};
+
+// Add the version
+Galleria.version = VERSION;
+
+/**
+    A method for checking what version of Galleria the user has installed and throws a readable error if the user needs to upgrade.
+    Useful when building plugins that requires a certain version to function.
+
+    @param {number} version The minimum version required
+
+    @param {string} [msg] Optional message to display. If not specified, Galleria will throw a generic error.
+
+    @returns Galleria
+*/
+
+Galleria.requires = function( version, msg ) {
+    msg = msg || 'You need to upgrade Galleria to version ' + version + ' to use one or more components.';
+    if ( Galleria.version < version ) {
+        Galleria.raise(msg, true);
+    }
+    return Galleria;
+};
+
+/**
+    Adds preload, cache, scale and crop functionality
+
+    @constructor
+
+    @requires jQuery
+
+    @param {number} [id] Optional id to keep track of instances
+*/
+
+Galleria.Picture = function( id ) {
+
+    // save the id
+    this.id = id || null;
+
+    // the image should be null until loaded
+    this.image = null;
+
+    // Create a new container
+    this.container = Utils.create('galleria-image');
+
+    // add container styles
+    $( this.container ).css({
+        overflow: 'hidden',
+        position: 'relative' // for IE Standards mode
+    });
+
+    // saves the original measurements
+    this.original = {
+        width: 0,
+        height: 0
+    };
+
+    // flag when the image is ready
+    this.ready = false;
+
+    // flag for iframe Picture
+    this.isIframe = false;
+
+};
+
+Galleria.Picture.prototype = {
+
+    // the inherited cache object
+    cache: {},
+
+    // show the image on stage
+    show: function() {
+        Utils.show( this.image );
+    },
+
+    // hide the image
+    hide: function() {
+        Utils.moveOut( this.image );
+    },
+
+    clear: function() {
+        this.image = null;
+    },
+
+    /**
+        Checks if an image is in cache
+
+        @param {string} src The image source path, ex '/path/to/img.jpg'
+
+        @returns {boolean}
+    */
+
+    isCached: function( src ) {
+        return !!this.cache[src];
+    },
+
+    /**
+        Preloads an image into the cache
+
+        @param {string} src The image source path, ex '/path/to/img.jpg'
+
+        @returns Galleria.Picture
+    */
+
+    preload: function( src ) {
+        $( new Image() ).load((function(src, cache) {
+            return function() {
+                cache[ src ] = src;
+            };
+        }( src, this.cache ))).attr( 'src', src );
+    },
+
+    /**
+        Loads an image and call the callback when ready.
+        Will also add the image to cache.
+
+        @param {string} src The image source path, ex '/path/to/img.jpg'
+        @param {Object} [size] The forced size of the image, defined as an object { width: xx, height:xx }
+        @param {Function} callback The function to be executed when the image is loaded & scaled
+
+        @returns The image container (jQuery object)
+    */
+
+    load: function(src, size, callback) {
+
+        if ( typeof size == 'function' ) {
+            callback = size;
+            size = null;
+        }
+
+        if( this.isIframe ) {
+            var id = 'if'+new Date().getTime();
+
+            var iframe = this.image = $('<iframe>', {
+                src: src,
+                frameborder: 0,
+                id: id,
+                allowfullscreen: true,
+                css: { visibility: 'hidden' }
+            })[0];
+
+            if ( size ) {
+                $( iframe ).css( size );
+            }
+
+            $( this.container ).find( 'iframe,img' ).remove();
+
+            this.container.appendChild( this.image );
+
+            $('#'+id).load( (function( self, callback ) {
+                return function() {
+                    window.setTimeout(function() {
+                        $( self.image ).css( 'visibility', 'visible' );
+                        if( typeof callback == 'function' ) {
+                            callback.call( self, self );
+                        }
+                    }, 10);
+                };
+            }( this, callback )));
+
+            return this.container;
+        }
+
+        this.image = new Image();
+
+        // IE8 opacity inherit bug
+        if ( Galleria.IE8 ) {
+            $( this.image ).css( 'filter', 'inherit' );
+        }
+
+        var reload = false,
+            resort = false,
+
+            // some jquery cache
+            $container = $( this.container ),
+            $image = $( this.image ),
+
+            onerror = function() {
+                if ( !reload ) {
+                    reload = true;
+                    // reload the image with a timestamp
+                    window.setTimeout((function(image, src) {
+                        return function() {
+                            image.attr('src', src + '?' + Utils.timestamp() );
+                        };
+                    }( $(this), src )), 50);
+                } else {
+                    // apply the dummy image if it exists
+                    if ( DUMMY ) {
+                        $( this ).attr( 'src', DUMMY );
+                    } else {
+                        Galleria.raise('Image not found: ' + src);
+                    }
+                }
+            },
+
+            // the onload method
+            onload = (function( self, callback, src ) {
+
+                return function() {
+
+                    var complete = function() {
+
+                        $( this ).unbind( 'load' );
+
+                        // save the original size
+                        self.original = size || {
+                            height: this.height,
+                            width: this.width
+                        };
+
+                        // translate3d if needed
+                        if ( Galleria.HAS3D ) {
+                            this.style.MozTransform = this.style.webkitTransform = 'translate3d(0,0,0)';
+                        }
+
+                        $container.append( this );
+
+                        self.cache[ src ] = src; // will override old cache
+
+                        if (typeof callback == 'function' ) {
+                            window.setTimeout(function() {
+                                callback.call( self, self );
+                            },1);
+                        }
+                    };
+
+                    // Delay the callback to "fix" the Adblock Bug
+                    // http://code.google.com/p/adblockforchrome/issues/detail?id=3701
+                    if ( ( !this.width || !this.height ) ) {
+                        window.setTimeout( (function( img ) {
+                            return function() {
+                                if ( img.width && img.height ) {
+                                    complete.call( img );
+                                } else {
+                                    // last resort, this should never happen but just in case it does...
+                                    if ( !resort ) {
+                                        $(new Image()).load( onload ).attr( 'src', img.src );
+                                        resort = true;
+                                    } else {
+                                        Galleria.raise('Could not extract width/height from image: ' + img.src +
+                                            '. Traced measures: width:' + img.width + 'px, height: ' + img.height + 'px.');
+                                    }
+                                }
+                            };
+                        }( this )), 2);
+                    } else {
+                        complete.call( this );
+                    }
+                };
+            }( this, callback, src ));
+
+        // remove any previous images
+        $container.find( 'iframe,img' ).remove();
+
+        // append the image
+        $image.css( 'display', 'block');
+
+        // hide it for now
+        Utils.hide( this.image );
+
+        // remove any max/min scaling
+        $.each('minWidth minHeight maxWidth maxHeight'.split(' '), function(i, prop) {
+            $image.css(prop, (/min/.test(prop) ? '0' : 'none'));
+        });
+
+        // begin load and insert in cache when done
+        $image.load( onload ).bind( 'error', onerror ).attr( 'src', src );
+
+        // return the container
+        return this.container;
+    },
+
+    /**
+        Scales and crops the image
+
+        @param {Object} options The method takes an object with a number of options:
+
+        <ul>
+            <li>width - width of the container</li>
+            <li>height - height of the container</li>
+            <li>min - minimum scale ratio</li>
+            <li>max - maximum scale ratio</li>
+            <li>margin - distance in pixels from the image border to the container</li>
+            <li>complete - a callback that fires when scaling is complete</li>
+            <li>position - positions the image, works like the css background-image property.</li>
+            <li>crop - defines how to crop. Can be true, false, 'width' or 'height'</li>
+            <li>canvas - set to true to try a canvas-based rescale</li>
+        </ul>
+
+        @returns The image container object (jQuery)
+    */
+
+    scale: function( options ) {
+
+        var self = this;
+
+        // extend some defaults
+        options = $.extend({
+            width: 0,
+            height: 0,
+            min: undef,
+            max: undef,
+            margin: 0,
+            complete: F,
+            position: 'center',
+            crop: false,
+            canvas: false,
+            iframelimit: undef
+        }, options);
+
+        if( this.isIframe ) {
+
+            var cw = options.width,
+                ch = options.height,
+                nw, nh;
+            if ( options.iframelimit ) {
+                var r = M.min( options.iframelimit/cw, options.iframelimit/ch );
+                if ( r < 1 ) {
+                    nw = cw * r;
+                    nh = ch * r;
+
+                    $( this.image ).css({
+                        top: ch/2-nh/2,
+                        left: cw/2-nw/2,
+                        position: 'absolute'
+                    });
+                } else {
+                    $( this.image ).css({
+                        top: 0,
+                        left: 0
+                    });
+                }
+            }
+            $( this.image ).width( nw || cw ).height( nh || ch ).removeAttr( 'width' ).removeAttr( 'height' );
+            $( this.container ).width( cw ).height( ch );
+            options.complete.call(self, self);
+            try {
+                if( this.image.contentWindow ) {
+                    $( this.image.contentWindow ).trigger('resize');
+                }
+            } catch(e) {}
+            return this.container;
+
+        }
+
+        // return the element if no image found
+        if (!this.image) {
+            return this.container;
+        }
+
+        // store locale variables
+        var width,
+            height,
+            $container = $( self.container ),
+            data;
+
+        // wait for the width/height
+        Utils.wait({
+            until: function() {
+                width  = options.width ||
+                         $container.width() ||
+                         Utils.parseValue( $container.css('width') );
+
+                height = options.height ||
+                         $container.height() ||
+                         Utils.parseValue( $container.css('height') );
+
+                return width && height;
+            },
+            success: function() {
+
+                // calculate some cropping
+                var newWidth = ( width - options.margin * 2 ) / self.original.width,
+                    newHeight = ( height - options.margin * 2 ) / self.original.height,
+                    min = M.min( newWidth, newHeight ),
+                    max = M.max( newWidth, newHeight ),
+                    cropMap = {
+                        'true'  : max,
+                        'width' : newWidth,
+                        'height': newHeight,
+                        'false' : min,
+                        'landscape': self.original.width > self.original.height ? max : min,
+                        'portrait': self.original.width < self.original.height ? max : min
+                    },
+                    ratio = cropMap[ options.crop.toString() ],
+                    canvasKey = '';
+
+                // allow maxScaleRatio
+                if ( options.max ) {
+                    ratio = M.min( options.max, ratio );
+                }
+
+                // allow minScaleRatio
+                if ( options.min ) {
+                    ratio = M.max( options.min, ratio );
+                }
+
+                $.each( ['width','height'], function( i, m ) {
+                    $( self.image )[ m ]( self[ m ] = self.image[ m ] = M.round( self.original[ m ] * ratio ) );
+                });
+
+                $( self.container ).width( width ).height( height );
+
+                if ( options.canvas && _canvas ) {
+
+                    _canvas.elem.width = self.width;
+                    _canvas.elem.height = self.height;
+
+                    canvasKey = self.image.src + ':' + self.width + 'x' + self.height;
+
+                    self.image.src = _canvas.cache[ canvasKey ] || (function( key ) {
+
+                        _canvas.context.drawImage(self.image, 0, 0, self.original.width*ratio, self.original.height*ratio);
+
+                        try {
+
+                            data = _canvas.elem.toDataURL();
+                            _canvas.length += data.length;
+                            _canvas.cache[ key ] = data;
+                            return data;
+
+                        } catch( e ) {
+                            return self.image.src;
+                        }
+
+                    }( canvasKey ) );
+
+                }
+
+                // calculate image_position
+                var pos = {},
+                    mix = {},
+                    getPosition = function(value, measure, margin) {
+                        var result = 0;
+                        if (/\%/.test(value)) {
+                            var flt = parseInt( value, 10 ) / 100,
+                                m = self.image[ measure ] || $( self.image )[ measure ]();
+
+                            result = M.ceil( m * -1 * flt + margin * flt );
+                        } else {
+                            result = Utils.parseValue( value );
+                        }
+                        return result;
+                    },
+                    positionMap = {
+                        'top': { top: 0 },
+                        'left': { left: 0 },
+                        'right': { left: '100%' },
+                        'bottom': { top: '100%' }
+                    };
+
+                $.each( options.position.toLowerCase().split(' '), function( i, value ) {
+                    if ( value === 'center' ) {
+                        value = '50%';
+                    }
+                    pos[i ? 'top' : 'left'] = value;
+                });
+
+                $.each( pos, function( i, value ) {
+                    if ( positionMap.hasOwnProperty( value ) ) {
+                        $.extend( mix, positionMap[ value ] );
+                    }
+                });
+
+                pos = pos.top ? $.extend( pos, mix ) : mix;
+
+                pos = $.extend({
+                    top: '50%',
+                    left: '50%'
+                }, pos);
+
+                // apply position
+                $( self.image ).css({
+                    position : 'absolute',
+                    top :  getPosition(pos.top, 'height', height),
+                    left : getPosition(pos.left, 'width', width)
+                });
+
+                // show the image
+                self.show();
+
+                // flag ready and call the callback
+                self.ready = true;
+                options.complete.call( self, self );
+
+            },
+            error: function() {
+                Galleria.raise('Could not scale image: '+self.image.src);
+            },
+            timeout: 1000
+        });
+        return this;
+    }
+};
+
+// our own easings
+$.extend( $.easing, {
+
+    galleria: function (_, t, b, c, d) {
+        if ((t/=d/2) < 1) {
+            return c/2*t*t*t + b;
+        }
+        return c/2*((t-=2)*t*t + 2) + b;
+    },
+
+    galleriaIn: function (_, t, b, c, d) {
+        return c*(t/=d)*t + b;
+    },
+
+    galleriaOut: function (_, t, b, c, d) {
+        return -c *(t/=d)*(t-2) + b;
+    }
+
+});
+
+// fastclick, for faster touch interactions
+// loosely based on FastClick by FTLabs (Financial Times)
+
+Galleria.Fastclick = (function() {
+
+    var deviceIsIOS = /iP(ad|hone|od)/.test(navigator.userAgent),
+        deviceIsIOS4 = deviceIsIOS && (/OS 4_\d(_\d)?/).test(navigator.userAgent),
+        deviceIsIOSWithBadTarget = deviceIsIOS && (/OS ([6-9]|\d{2})_\d/).test(navigator.userAgent);
+
+    return {
+        init: function(layer) {
+            var oldOnClick, self = this;
+            this.trackingClick = false;
+            this.trackingClickStart = 0;
+            this.targetElement = null;
+            this.touchStartX = 0;
+            this.touchStartY = 0;
+            this.lastTouchIdentifier = 0;
+            this.layer = layer;
+
+            $.each(['Click', 'TouchStart', 'TouchMove', 'TouchEnd', 'TouchCancel'], function(i, fn) {
+                self['on'+fn] = (function(caller) {
+                    return function() {
+                        caller.apply( self, arguments );
+                    };
+                }(self['on'+fn]));
+            });
+
+            if (!Galleria.TOUCH) {
+                return;
+            }
+
+            // Set up event handlers as required
+            layer.addEventListener('click', this.onClick, true);
+            layer.addEventListener('touchstart', this.onTouchStart, false);
+            layer.addEventListener('touchmove', this.onTouchMove, false);
+            layer.addEventListener('touchend', this.onTouchEnd, false);
+            layer.addEventListener('touchcancel', this.onTouchCancel, false);
+
+            if (!window.Event.prototype.stopImmediatePropagation) {
+                layer.removeEventListener = function(type, callback, capture) {
+                    var rmv = window.Node.prototype.removeEventListener;
+                    if (type === 'click') {
+                        rmv.call(layer, type, callback.hijacked || callback, capture);
+                    } else {
+                        rmv.call(layer, type, callback, capture);
+                    }
+                };
+                layer.addEventListener = function(type, callback, capture) {
+                    var adv = window.Node.prototype.addEventListener;
+                    if (type === 'click') {
+                        adv.call(layer, type, callback.hijacked || (callback.hijacked = function(event) {
+                            if (!event.propagationStopped) {
+                                callback(event);
+                            }
+                        }), capture);
+                    } else {
+                        adv.call(layer, type, callback, capture);
+                    }
+                };
+            }
+            if (typeof layer.onclick === 'function') {
+                oldOnClick = layer.onclick;
+                layer.addEventListener('click', function(event) {
+                    oldOnClick(event);
+                }, false);
+                layer.onclick = null;
+            }
+
+        },
+        sendClick: function(targetElement, event) {
+            var clickEvent, touch;
+
+            if (doc.activeElement && doc.activeElement !== targetElement) {
+                doc.activeElement.blur();
+            }
+
+            touch = event.changedTouches[0];
+
+            // Synthesise a click event, with an extra attribute so it can be tracked
+            clickEvent = doc.createEvent('MouseEvents');
+            clickEvent.initMouseEvent('click', true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);
+            clickEvent.forwardedTouchEvent = true;
+            targetElement.dispatchEvent(clickEvent);
+        },
+        onTouchStart: function(event) {
+            var targetElement, touch, selection;
+
+            targetElement = event.target;
+            touch = event.targetTouches[0];
+
+            if (deviceIsIOS) {
+
+                selection = window.getSelection();
+                if (selection.rangeCount && !selection.isCollapsed) {
+                    return true;
+                }
+
+                if (!deviceIsIOS4) {
+                    if (touch.identifier === this.lastTouchIdentifier) {
+                        event.preventDefault();
+                        return false;
+                    }
+
+                    this.lastTouchIdentifier = touch.identifier;
+                }
+            }
+
+            this.trackingClick = true;
+            this.trackingClickStart = event.timeStamp;
+            this.targetElement = targetElement;
+
+            this.touchStartX = touch.pageX;
+            this.touchStartY = touch.pageY;
+
+            if ((event.timeStamp - this.lastClickTime) < 200) {
+                event.preventDefault();
+            }
+
+            return true;
+        },
+        touchHasMoved: function(event) {
+            var touch = event.targetTouches[0];
+
+            if (M.abs(touch.pageX - this.touchStartX) > 10 || M.abs(touch.pageY - this.touchStartY) > 10) {
+                return true;
+            }
+
+            return false;
+        },
+        onTouchMove: function(event) {
+            if (!this.trackingClick) {
+                return true;
+            }
+
+            // If the touch has moved, cancel the click tracking
+            if (this.targetElement !== event.target || this.touchHasMoved(event)) {
+                this.trackingClick = false;
+                this.targetElement = null;
+            }
+
+            return true;
+        },
+        onTouchEnd: function(event) {
+            var trackingClickStart, targetTagName, touch, targetElement = this.targetElement;
+
+            if (!this.trackingClick) {
+                return true;
+            }
+
+            // Prevent phantom clicks on fast double-tap (issue #36)
+            if ((event.timeStamp - this.lastClickTime) < 200) {
+                this.cancelNextClick = true;
+                return true;
+            }
+
+            this.lastClickTime = event.timeStamp;
+
+            trackingClickStart = this.trackingClickStart;
+            this.trackingClick = false;
+            this.trackingClickStart = 0;
+
+            if (deviceIsIOSWithBadTarget) {
+                touch = event.changedTouches[0];
+                targetElement = event.target;
+                targetElement = doc.elementFromPoint(touch.pageX - window.pageXOffset, touch.pageY - window.pageYOffset);
+            }
+
+            targetTagName = targetElement.tagName.toLowerCase();
+
+            event.preventDefault();
+            this.sendClick(targetElement, event);
+
+            return false;
+        },
+        onTouchCancel: function() {
+            this.trackingClick = false;
+            this.targetElement = null;
+        },
+        onClick: function(event) {
+            var oldTargetElement;
+
+            // If a target element was never set (because a touch event was never fired) allow the click
+            if (!this.targetElement) {
+                return true;
+            }
+
+            if (event.forwardedTouchEvent) {
+                return true;
+            }
+
+            oldTargetElement = this.targetElement;
+            this.targetElement = null;
+
+            if (this.trackingClick) {
+                this.trackingClick = false;
+                return true;
+            }
+
+            // Programmatically generated events targeting a specific element should be permitted
+            if (!event.cancelable) {
+                return true;
+            }
+
+            if (this.cancelNextClick) {
+                this.cancelNextClick = false;
+
+                // Prevent any user-added listeners declared on FastClick element from being fired.
+                if (event.stopImmediatePropagation) {
+                    event.stopImmediatePropagation();
+                } else {
+
+                    // Part of the hack for browsers that don't support Event#stopImmediatePropagation (e.g. Android 2)
+                    event.propagationStopped = true;
+                }
+
+                // Cancel the event
+                event.stopPropagation();
+                event.preventDefault();
+
+                return false;
+            }
+            return true;
+        }
+    };
+}());
+
+// Forked version of Ainos Finger.js for native-style touch
+
+Galleria.Finger = (function() {
+
+    var abs = M.abs;
+
+    // test for translate3d support
+    var has3d = Galleria.HAS3D = (function() {
+
+        var el = doc.createElement('p'),
+            has3d,
+            t = ['webkit','O','ms','Moz',''], s, i=0, a = 'transform';
+
+        DOM().html.insertBefore(el, null);
+
+        for (; t[i]; i++) {
+            s = t[i] ? t[i]+'Transform' : a;
+            if (el.style[s] !== undefined) {
+                el.style[s] = "translate3d(1px,1px,1px)";
+                has3d = $(el).css(t[i] ? '-'+t[i].toLowerCase()+'-'+a : a);
+            }
+        }
+
+        DOM().html.removeChild(el);
+        return (has3d !== undefined && has3d.length > 0 && has3d !== "none");
+    }());
+
+    // request animation shim
+    var requestFrame = (function(){
+        var r = 'RequestAnimationFrame';
+        return window.requestAnimationFrame ||
+               window['webkit'+r] ||
+               window['moz'+r] ||
+               window['o'+r] ||
+               window['ms'+r] ||
+               function( callback ) {
+                   window.setTimeout(callback, 1000 / 60);
+               };
+    }());
+
+    var Finger = function(elem, options) {
+
+        // default options
+        this.config = {
+            start: 0,
+            duration: 500,
+            onchange: function() {},
+            oncomplete: function() {},
+            easing: function(x,t,b,c,d) {
+                return -c * ((t=t/d-1)*t*t*t - 1) + b; // easeOutQuart
+            }
+        };
+
+        if ( !elem.children.length ) {
+            return;
+        }
+
+        var self = this;
+
+        // extend options
+        $.extend(this.config, options);
+
+        this.elem = elem;
+        this.child = elem.children[0];
+        this.to = this.pos = 0;
+        this.touching = false;
+        this.start = {};
+        this.index = this.config.start;
+        this.anim = 0;
+
+        if ( !has3d ) {
+          this.child.style.position = 'absolute';
+          this.elem.style.position = 'relative';
+        }
+
+        // Bind event handlers to context
+        $.each(['ontouchstart','ontouchmove','ontouchend','setup'], function(i, fn) {
+            self[fn] = (function(caller) {
+                return function() {
+                    caller.apply( self, arguments );
+                };
+            }(self[fn]));
+        });
+
+        // the physical animator
+        this.setX = function() {
+
+            var style = self.child.style;
+
+            if (!has3d) {
+                // this is actually faster than CSS3 translate
+                style.left = self.pos+'px';
+                return;
+            }
+            style.MozTransform = style.webkitTransform = 'translate3d(' + self.pos + 'px,0,0)';
+            return;
+        };
+
+        // bind events
+        $(elem).bind('touchstart', this.ontouchstart);
+        $(window).bind('resize', this.setup);
+        $(window).bind('orientationchange', this.setup);
+
+        // set up width
+        this.setup();
+
+        // start the animations
+        (function animloop(){
+          requestFrame(animloop);
+          self.loop.call( self );
+        }());
+
+    };
+
+    Finger.prototype = {
+
+        constructor: Finger,
+
+        setup: function() {
+            this.width = $( this.elem ).width();
+            this.length = M.ceil( $(this.child).width() / this.width );
+            if ( this.index !== 0 ) {
+                this.index = M.max(0, M.min( this.index, this.length-1 ) );
+                this.pos = this.to = -this.width*this.index;
+            }
+        },
+
+        setPosition: function(pos) {
+            this.pos = pos;
+            this.to = pos;
+        },
+
+        ontouchstart: function(e) {
+
+            var touch = e.originalEvent.touches;
+
+            this.start = {
+                pageX: touch[0].pageX,
+                pageY: touch[0].pageY,
+                time:  +new Date()
+            };
+
+            this.isScrolling = null;
+            this.touching = true;
+            this.deltaX = 0;
+
+            $doc.bind('touchmove', this.ontouchmove);
+            $doc.bind('touchend', this.ontouchend);
+        },
+
+        ontouchmove: function(e) {
+
+            var touch = e.originalEvent.touches;
+
+            // ensure swiping with one touch and not pinching
+            if( touch && touch.length > 1 || e.scale && e.scale !== 1 ) {
+                return;
+            }
+
+            this.deltaX = touch[0].pageX - this.start.pageX;
+
+            // determine if scrolling test has run - one time test
+            if ( this.isScrolling === null ) {
+                this.isScrolling = !!(
+                    this.isScrolling ||
+                    abs(this.deltaX) < abs(touch[0].pageY - this.start.pageY)
+                );
+            }
+
+            // if user is not trying to scroll vertically
+            if (!this.isScrolling) {
+
+                // prevent native scrolling
+                e.preventDefault();
+
+                // increase resistance if first or last slide
+                this.deltaX /= ( (!this.index && this.deltaX > 0 || this.index == this.length - 1 && this.deltaX < 0 ) ?
+                    ( abs(this.deltaX) / this.width + 1.8 )  : 1 );
+                this.to = this.deltaX - this.index * this.width;
+            }
+            e.stopPropagation();
+        },
+
+        ontouchend: function(e) {
+
+            this.touching = false;
+
+            // determine if slide attempt triggers next/prev slide
+            var isValidSlide = +new Date() - this.start.time < 250 &&
+                abs(this.deltaX) > 40 ||
+                abs(this.deltaX) > this.width/2,
+
+                isPastBounds = !this.index && this.deltaX > 0 ||
+                    this.index == this.length - 1 && this.deltaX < 0;
+
+            // if not scrolling vertically
+            if ( !this.isScrolling ) {
+                this.show( this.index + ( isValidSlide && !isPastBounds ? (this.deltaX < 0 ? 1 : -1) : 0 ) );
+            }
+
+            $doc.unbind('touchmove', this.ontouchmove);
+            $doc.unbind('touchend', this.ontouchend);
+        },
+
+        show: function( index ) {
+            if ( index != this.index ) {
+                this.config.onchange.call(this, index);
+            } else {
+                this.to = -( index*this.width );
+            }
+        },
+
+        moveTo: function( index ) {
+            if ( index != this.index ) {
+                this.pos = this.to = -( index*this.width );
+                this.index = index;
+            }
+        },
+
+        loop: function() {
+
+            var distance = this.to - this.pos,
+                factor = 1;
+
+            if ( this.width && distance ) {
+                factor = M.max(0.5, M.min(2, M.abs(distance / this.width) ) );
+            }
+
+            // if distance is short or the user is touching, do a 1-1 animation
+            if ( this.touching || abs(distance) <= 1 ) {
+              this.pos = this.to;
+              if ( this.anim ) {
+                this.config.oncomplete( this.index );
+              }
+              this.anim = 0;
+            } else {
+                if ( !this.anim ) {
+                    // save animation parameters
+                    this.anim = { v: this.pos, c: distance, t: +new Date(), f: factor };
+                }
+                // apply easing
+                this.pos = this.config.easing(null, +new Date() - this.anim.t, this.anim.v, this.anim.c, this.config.duration*this.anim.f);
+            }
+            this.setX();
+        }
+    };
+
+    return Finger;
+
+}());
+
+// the plugin initializer
+$.fn.galleria = function( options ) {
+
+    var selector = this.selector;
+
+    // try domReady if element not found
+    if ( !$(this).length ) {
+
+        $(function() {
+            if ( $( selector ).length ) {
+
+                // if found on domReady, go ahead
+                $( selector ).galleria( options );
+
+            } else {
+
+                // if not, try fetching the element for 5 secs, then raise a warning.
+                Galleria.utils.wait({
+                    until: function() {
+                        return $( selector ).length;
+                    },
+                    success: function() {
+                        $( selector ).galleria( options );
+                    },
+                    error: function() {
+                        Galleria.raise('Init failed: Galleria could not find the element "'+selector+'".');
+                    },
+                    timeout: 5000
+                });
+
+            }
+        });
+        return this;
+    }
+
+    return this.each(function() {
+
+        // destroy previous instance and prepare for new load
+        if ( $.data(this, 'galleria') ) {
+            $.data( this, 'galleria' ).destroy();
+            $( this ).find( '*' ).hide();
+        }
+
+        // load the new gallery
+        $.data( this, 'galleria', new Galleria().init( this, options ) );
+    });
+
+};
+
+// phew
+
+}( jQuery ) );
\ No newline at end of file
diff --git a/doc/_static/galleria/galleria-1.3.2.min.js b/doc/_static/galleria/galleria-1.3.2.min.js
new file mode 100644
index 0000000..713a4ab
--- /dev/null
+++ b/doc/_static/galleria/galleria-1.3.2.min.js
@@ -0,0 +1,3 @@
+!function(t,e,i){var n=this,a=n.document,r=t(a),o=t(n),s=Array.prototype,l=1.32,c=true,u=3e4,h=false,f=navigator.userAgent.toLowerCase(),d=n.location.hash.replace(/#\//,""),p=n.location.protocol,g=Math,m=function(){},v=function(){return false},y=function(){var t=3,e=a.createElement("div"),n=e.getElementsByTagName("i");do{e.innerHTML="<!--[if gt IE "+ ++t+"]><i></i><![endif]-->"}while(n[0]);return t>4?t:i}(),b=function(){return{html:a.documentElement,body:a.body,head:a.getElementsByTagNam [...]
+}if(typeof e.theme==="object"){this._init()}else{P.push(this)}return this},_init:function(){var r=this,s=this._options;if(this._initialized){e.raise("Init failed: Gallery instance already initialized.");return this}this._initialized=true;if(!e.theme){e.raise("Init failed: No theme found.",true);return this}t.extend(true,s,e.theme.defaults,this._original.options,e.configure.options);if(s.swipe){s.clicknext=false;s.imagePan=false}!function(t){if(!("getContext"in t)){t=null;return}$=$||{ele [...]
+},hide:function(){H.moveOut(this.image)},clear:function(){this.image=null},isCached:function(t){return!!this.cache[t]},preload:function(e){t(new Image).load(function(t,e){return function(){e[t]=t}}(e,this.cache)).attr("src",e)},load:function(i,a,r){if(typeof a=="function"){r=a;a=null}if(this.isIframe){var o="if"+(new Date).getTime();var s=this.image=t("<iframe>",{src:i,frameborder:0,id:o,allowfullscreen:true,css:{visibility:"hidden"}})[0];if(a){t(s).css(a)}t(this.container).find("iframe, [...]
\ No newline at end of file
diff --git a/doc/_static/galleria/themes/classic/classic-demo.html b/doc/_static/galleria/themes/classic/classic-demo.html
new file mode 100644
index 0000000..f9d6f83
--- /dev/null
+++ b/doc/_static/galleria/themes/classic/classic-demo.html
@@ -0,0 +1,124 @@
+<!DOCTYPE html>
+<html lang="en">
+    <head>
+        <meta charset="utf-8">
+        <title>Galleria Classic Theme</title>
+        <style>
+
+            /* Demo styles */
+            html,body{background:#222;margin:0;}
+            body{border-top:4px solid #000;}
+            .content{color:#777;font:12px/1.4 "helvetica neue",arial,sans-serif;width:620px;margin:20px auto;}
+            h1{font-size:12px;font-weight:normal;color:#ddd;margin:0;}
+            p{margin:0 0 20px}
+            a {color:#22BCB9;text-decoration:none;}
+            .cred{margin-top:20px;font-size:11px;}
+
+            /* This rule is read by Galleria to define the gallery height: */
+            #galleria{height:320px}
+
+        </style>
+
+        <!-- load jQuery -->
+        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.js"></script>
+
+        <!-- load Galleria -->
+        <script src="../../galleria-1.3.2.min.js"></script>
+
+    </head>
+<body>
+    <div class="content">
+        <h1>Galleria Classic Theme</h1>
+        <p>Demonstrating a basic gallery example.</p>
+
+        <!-- Adding gallery images. We use resized thumbnails here for better performance, but it’s not necessary -->
+
+        <div id="galleria">
+            <a href="http://upload.wikimedia.org/wikipedia/commons/thumb/a/a2/Biandintz_eta_zaldiak_-_modified2.jpg/800px-Biandintz_eta_zaldiak_-_modified2.jpg">
+                <img 
+                    src="http://upload.wikimedia.org/wikipedia/commons/thumb/a/a2/Biandintz_eta_zaldiak_-_modified2.jpg/100px-Biandintz_eta_zaldiak_-_modified2.jpg",
+                    data-big="http://upload.wikimedia.org/wikipedia/commons/thumb/a/a2/Biandintz_eta_zaldiak_-_modified2.jpg/1280px-Biandintz_eta_zaldiak_-_modified2.jpg"
+                    data-title="Biandintz eta zaldiak"
+                    data-description="Horses on Bianditz mountain, in Navarre, Spain."
+                >
+            </a>
+            <a href="http://upload.wikimedia.org/wikipedia/commons/thumb/6/6c/Athabasca_Rail_at_Brule_Lake.jpg/800px-Athabasca_Rail_at_Brule_Lake.jpg">
+                <img 
+                    src="http://upload.wikimedia.org/wikipedia/commons/thumb/6/6c/Athabasca_Rail_at_Brule_Lake.jpg/100px-Athabasca_Rail_at_Brule_Lake.jpg",
+                    data-big="http://upload.wikimedia.org/wikipedia/commons/thumb/6/6c/Athabasca_Rail_at_Brule_Lake.jpg/1280px-Athabasca_Rail_at_Brule_Lake.jpg"
+                    data-title="Athabasca Rail"
+                    data-description="The Athabasca River railroad track at the mouth of Brulé Lake in Alberta, Canada."
+                >
+            </a>
+            <a href="http://upload.wikimedia.org/wikipedia/commons/thumb/1/1f/Back-scattering_crepuscular_rays_panorama_1.jpg/1280px-Back-scattering_crepuscular_rays_panorama_1.jpg">
+                <img 
+                    src="http://upload.wikimedia.org/wikipedia/commons/thumb/1/1f/Back-scattering_crepuscular_rays_panorama_1.jpg/100px-Back-scattering_crepuscular_rays_panorama_1.jpg",
+                    data-big="http://upload.wikimedia.org/wikipedia/commons/thumb/1/1f/Back-scattering_crepuscular_rays_panorama_1.jpg/1400px-Back-scattering_crepuscular_rays_panorama_1.jpg"
+                    data-title="Back-scattering crepuscular rays"
+                    data-description="Picture of the day on Wikimedia Commons 26 September 2010."
+                >
+            </a>
+            <a href="http://upload.wikimedia.org/wikipedia/commons/thumb/7/75/Interior_convento_3.jpg/800px-Interior_convento_3.jpg">
+                <img 
+                    src="http://upload.wikimedia.org/wikipedia/commons/thumb/7/75/Interior_convento_3.jpg/120px-Interior_convento_3.jpg",
+                    data-big="http://upload.wikimedia.org/wikipedia/commons/thumb/7/75/Interior_convento_3.jpg/1400px-Interior_convento_3.jpg"
+                    data-title="Interior convento"
+                    data-description="Interior view of Yuriria Convent, founded in 1550."
+                >
+            </a>
+            <a href="http://upload.wikimedia.org/wikipedia/commons/thumb/6/6b/Oxbow_Bend_outlook_in_the_Grand_Teton_National_Park.jpg/800px-Oxbow_Bend_outlook_in_the_Grand_Teton_National_Park.jpg">
+                <img 
+                    src="http://upload.wikimedia.org/wikipedia/commons/thumb/6/6b/Oxbow_Bend_outlook_in_the_Grand_Teton_National_Park.jpg/100px-Oxbow_Bend_outlook_in_the_Grand_Teton_National_Park.jpg",
+                    data-big="http://upload.wikimedia.org/wikipedia/commons/thumb/6/6b/Oxbow_Bend_outlook_in_the_Grand_Teton_National_Park.jpg/1280px-Oxbow_Bend_outlook_in_the_Grand_Teton_National_Park.jpg"
+                    data-title="Oxbow Bend outlook"
+                    data-description="View over the Snake River to the Mount Moran with the Skillet Glacier."
+                >
+            </a>
+            <a href="http://upload.wikimedia.org/wikipedia/commons/thumb/c/c9/Hazy_blue_hour_in_Grand_Canyon.JPG/800px-Hazy_blue_hour_in_Grand_Canyon.JPG">
+                <img 
+                    src="http://upload.wikimedia.org/wikipedia/commons/thumb/c/c9/Hazy_blue_hour_in_Grand_Canyon.JPG/100px-Hazy_blue_hour_in_Grand_Canyon.JPG",
+                    data-big="http://upload.wikimedia.org/wikipedia/commons/thumb/c/c9/Hazy_blue_hour_in_Grand_Canyon.JPG/1280px-Hazy_blue_hour_in_Grand_Canyon.JPG"
+                    data-title="Hazy blue hour"
+                    data-description="Hazy blue hour in Grand Canyon. View from the South Rim."
+                >
+            </a>
+            <a href="http://upload.wikimedia.org/wikipedia/commons/thumb/f/f4/2909_vallon_moy_res.jpg/800px-2909_vallon_moy_res.jpg">
+                <img 
+                    src="http://upload.wikimedia.org/wikipedia/commons/thumb/f/f4/2909_vallon_moy_res.jpg/100px-2909_vallon_moy_res.jpg",
+                    data-big="http://upload.wikimedia.org/wikipedia/commons/thumb/f/f4/2909_vallon_moy_res.jpg/1280px-2909_vallon_moy_res.jpg"
+                    data-title="Haute Severaisse valley"
+                    data-description="View of Haute Severaisse valley and surrounding summits from the slopes of Les Vernets."
+                >
+            </a>
+            <a href="http://upload.wikimedia.org/wikipedia/commons/thumb/4/46/Bohinjsko_jezero_2.jpg/800px-Bohinjsko_jezero_2.jpg">
+                <img 
+                    src="http://upload.wikimedia.org/wikipedia/commons/thumb/4/46/Bohinjsko_jezero_2.jpg/100px-Bohinjsko_jezero_2.jpg",
+                    data-big="http://upload.wikimedia.org/wikipedia/commons/thumb/4/46/Bohinjsko_jezero_2.jpg/1280px-Bohinjsko_jezero_2.jpg"
+                    data-title="Bohinj lake"
+                    data-description="Bohinj lake (Triglav National Park, Slovenia) in the morning."
+                >
+            </a>
+            <a href="http://upload.wikimedia.org/wikipedia/commons/thumb/3/32/Bowling_Balls_Beach_2_edit.jpg/800px-Bowling_Balls_Beach_2_edit.jpg">
+                <img 
+                    src="http://upload.wikimedia.org/wikipedia/commons/thumb/3/32/Bowling_Balls_Beach_2_edit.jpg/100px-Bowling_Balls_Beach_2_edit.jpg",
+                    data-big="http://upload.wikimedia.org/wikipedia/commons/thumb/3/32/Bowling_Balls_Beach_2_edit.jpg/1280px-Bowling_Balls_Beach_2_edit.jpg"
+                    data-title="Bowling Balls"
+                    data-description="Mendocino county, California, USA."
+                >
+            </a>
+        </div>
+
+        <p class="cred">Made by <a href="http://galleria.aino.se">Galleria</a>.</p>
+    </div>
+
+    <script>
+
+    // Load the classic theme
+    Galleria.loadTheme('galleria.classic.min.js');
+
+    // Initialize Galleria
+    Galleria.run('#galleria');
+
+    </script>
+    </body>
+</html>
\ No newline at end of file
diff --git a/doc/_static/galleria/themes/classic/classic-loader.gif b/doc/_static/galleria/themes/classic/classic-loader.gif
new file mode 100644
index 0000000..27df81f
Binary files /dev/null and b/doc/_static/galleria/themes/classic/classic-loader.gif differ
diff --git a/doc/_static/galleria/themes/classic/classic-map.png b/doc/_static/galleria/themes/classic/classic-map.png
new file mode 100644
index 0000000..3b1d71c
Binary files /dev/null and b/doc/_static/galleria/themes/classic/classic-map.png differ
diff --git a/doc/_static/galleria/themes/classic/galleria.classic.css b/doc/_static/galleria/themes/classic/galleria.classic.css
new file mode 100644
index 0000000..f016d5b
--- /dev/null
+++ b/doc/_static/galleria/themes/classic/galleria.classic.css
@@ -0,0 +1,219 @@
+/* Galleria Classic Theme 2012-08-07 | https://raw.github.com/aino/galleria/master/LICENSE | (c) Aino */
+
+#galleria-loader{height:1px!important}
+
+.galleria-container {
+    position: relative;
+    overflow: hidden;
+    background: #000;
+}
+.galleria-container img {
+    -moz-user-select: none;
+    -webkit-user-select: none;
+    -o-user-select: none;
+}
+.galleria-stage {
+    position: absolute;
+    top: 10px;
+    bottom: 60px;
+    left: 10px;
+    right: 10px;
+    overflow:hidden;
+}
+.galleria-thumbnails-container {
+    height: 50px;
+    bottom: 0;
+    position: absolute;
+    left: 10px;
+    right: 10px;
+    z-index: 2;
+}
+.galleria-carousel .galleria-thumbnails-list {
+    margin-left: 30px;
+    margin-right: 30px;
+}
+.galleria-thumbnails .galleria-image {
+    height: 40px;
+    width: 60px;
+    background: #000;
+    margin: 0 5px 0 0;
+    border: 1px solid #000;
+    float: left;
+    cursor: pointer;
+}
+.galleria-counter {
+    position: absolute;
+    bottom: 10px;
+    left: 10px;
+    text-align: right;
+    color: #fff;
+    font: normal 11px/1 arial,sans-serif;
+    z-index: 1;
+}
+.galleria-loader {
+    background: #000;
+    width: 20px;
+    height: 20px;
+    position: absolute;
+    top: 10px;
+    right: 10px;
+    z-index: 2;
+    display: none;
+    background: url(classic-loader.gif) no-repeat 2px 2px;
+}
+.galleria-info {
+    width: 50%;
+    top: 15px;
+    left: 15px;
+    z-index: 2;
+    position: absolute;
+}
+.galleria-info-text {
+    background-color: #000;
+    padding: 12px;
+    display: none;
+    /* IE7 */ zoom:1;
+}
+.galleria-info-title {
+    font: bold 12px/1.1 arial,sans-serif;
+    margin: 0;
+    color: #fff;
+    margin-bottom: 7px;
+}
+.galleria-info-description {
+    font: italic 12px/1.4 georgia,serif;
+    margin: 0;
+    color: #bbb;
+}
+.galleria-info-close {
+    width: 9px;
+    height: 9px;
+    position: absolute;
+    top: 5px;
+    right: 5px;
+    background-position: -753px -11px;
+    opacity: .5;
+    filter: alpha(opacity=50);
+    cursor: pointer;
+    display: none;
+}
+.notouch .galleria-info-close:hover{
+    opacity:1;
+    filter: alpha(opacity=100);
+}
+.touch .galleria-info-close:active{
+    opacity:1;
+    filter: alpha(opacity=100);
+}
+.galleria-info-link {
+    background-position: -669px -5px;
+    opacity: .7;
+    filter: alpha(opacity=70);
+    position: absolute;
+    width: 20px;
+    height: 20px;
+    cursor: pointer;
+    background-color: #000;
+}
+.notouch .galleria-info-link:hover {
+    opacity: 1;
+    filter: alpha(opacity=100);
+}
+.touch .galleria-info-link:active {
+    opacity: 1;
+    filter: alpha(opacity=100);
+}
+.galleria-image-nav {
+    position: absolute;
+    top: 50%;
+    margin-top: -62px;
+    width: 100%;
+    height: 62px;
+    left: 0;
+}
+.galleria-image-nav-left,
+.galleria-image-nav-right {
+    opacity: .3;
+    filter: alpha(opacity=30);
+    cursor: pointer;
+    width: 62px;
+    height: 124px;
+    position: absolute;
+    left: 10px;
+    z-index: 2;
+    background-position: 0 46px;
+}
+.galleria-image-nav-right {
+    left: auto;
+    right: 10px;
+    background-position: -254px 46px;
+    z-index: 2;
+}
+.notouch .galleria-image-nav-left:hover,
+.notouch .galleria-image-nav-right:hover {
+    opacity: 1;
+    filter: alpha(opacity=100);
+}
+.touch .galleria-image-nav-left:active,
+.touch .galleria-image-nav-right:active {
+    opacity: 1;
+    filter: alpha(opacity=100);
+}
+.galleria-thumb-nav-left,
+.galleria-thumb-nav-right {
+    cursor: pointer;
+    display: none;
+    background-position: -495px 5px;
+    position: absolute;
+    left: 0;
+    top: 0;
+    height: 40px;
+    width: 23px;
+    z-index: 3;
+    opacity: .8;
+    filter: alpha(opacity=80);
+}
+.galleria-thumb-nav-right {
+    background-position: -578px 5px;
+    border-right: none;
+    right: 0;
+    left: auto;
+}
+.galleria-thumbnails-container .disabled {
+    opacity: .2;
+    filter: alpha(opacity=20);
+    cursor: default;
+}
+.notouch .galleria-thumb-nav-left:hover,
+.notouch .galleria-thumb-nav-right:hover {
+    opacity: 1;
+    filter: alpha(opacity=100);
+    background-color: #111;
+}
+.touch .galleria-thumb-nav-left:active,
+.touch .galleria-thumb-nav-right:active {
+    opacity: 1;
+    filter: alpha(opacity=100);
+    background-color: #111;
+}
+.notouch .galleria-thumbnails-container .disabled:hover {
+    opacity: .2;
+    filter: alpha(opacity=20);
+    background-color: transparent;
+}
+
+.galleria-carousel .galleria-thumb-nav-left,
+.galleria-carousel .galleria-thumb-nav-right {
+    display: block;
+}
+.galleria-thumb-nav-left,
+.galleria-thumb-nav-right,
+.galleria-info-link,
+.galleria-info-close,
+.galleria-image-nav-left,
+.galleria-image-nav-right {
+    background-image: url(classic-map.png);
+    background-repeat: no-repeat;
+}
+.galleria-container.videoplay .galleria-info,
+.galleria-container.videoplay .galleria-counter{ display:none!important; }
diff --git a/doc/_static/galleria/themes/classic/galleria.classic.js b/doc/_static/galleria/themes/classic/galleria.classic.js
new file mode 100644
index 0000000..670037f
--- /dev/null
+++ b/doc/_static/galleria/themes/classic/galleria.classic.js
@@ -0,0 +1,101 @@
+/**
+ * Galleria Classic Theme 2012-08-08
+ * http://galleria.io
+ *
+ * Licensed under the MIT license
+ * https://raw.github.com/aino/galleria/master/LICENSE
+ *
+ */
+
+(function($) {
+
+/*global window, jQuery, Galleria */
+
+Galleria.addTheme({
+    name: 'classic',
+    author: 'Galleria',
+    css: 'galleria.classic.css',
+    defaults: {
+        transition: 'slide',
+        thumbCrop:  'height',
+
+        // set this to false if you want to show the caption all the time:
+        _toggleInfo: true
+    },
+    init: function(options) {
+
+        Galleria.requires(1.28, 'This version of Classic theme requires Galleria 1.2.8 or later');
+
+        // add some elements
+        this.addElement('info-link','info-close');
+        this.append({
+            'info' : ['info-link','info-close']
+        });
+
+        // cache some stuff
+        var info = this.$('info-link,info-close,info-text'),
+            touch = Galleria.TOUCH,
+            click = touch ? 'touchstart' : 'click';
+
+        // show loader & counter with opacity
+        this.$('loader,counter').show().css('opacity', 0.4);
+
+        // some stuff for non-touch browsers
+        if (! touch ) {
+            this.addIdleState( this.get('image-nav-left'), { left:-50 });
+            this.addIdleState( this.get('image-nav-right'), { right:-50 });
+            this.addIdleState( this.get('counter'), { opacity:0 });
+        }
+
+        // toggle info
+        if ( options._toggleInfo === true ) {
+            info.bind( click, function() {
+                info.toggle();
+            });
+        } else {
+            info.show();
+            this.$('info-link, info-close').hide();
+        }
+
+        // bind some stuff
+        this.bind('thumbnail', function(e) {
+
+            if (! touch ) {
+                // fade thumbnails
+                $(e.thumbTarget).css('opacity', 0.6).parent().hover(function() {
+                    $(this).not('.active').children().stop().fadeTo(100, 1);
+                }, function() {
+                    $(this).not('.active').children().stop().fadeTo(400, 0.6);
+                });
+
+                if ( e.index === this.getIndex() ) {
+                    $(e.thumbTarget).css('opacity',1);
+                }
+            } else {
+                $(e.thumbTarget).css('opacity', this.getIndex() ? 1 : 0.6).click( function() {
+                    $(this).css( 'opacity', 1 ).parent().siblings().children().css('opacity', 0.6);
+                });
+            }
+        });
+
+        var activate = function(e) {
+            $(e.thumbTarget).css('opacity',1).parent().siblings().children().css('opacity', 0.6);
+        };
+
+        this.bind('loadstart', function(e) {
+            if (!e.cached) {
+                this.$('loader').show().fadeTo(200, 0.4);
+            }
+            window.setTimeout(function() {
+                activate(e);
+            }, touch ? 300 : 0);
+            this.$('info').toggle( this.hasInfo() );
+        });
+
+        this.bind('loadfinish', function(e) {
+            this.$('loader').fadeOut(200);
+        });
+    }
+});
+
+}(jQuery));
diff --git a/doc/_static/galleria/themes/classic/galleria.classic.min.js b/doc/_static/galleria/themes/classic/galleria.classic.min.js
new file mode 100644
index 0000000..edbd9bd
--- /dev/null
+++ b/doc/_static/galleria/themes/classic/galleria.classic.min.js
@@ -0,0 +1 @@
+!function(i){Galleria.addTheme({name:"classic",author:"Galleria",css:"galleria.classic.css",defaults:{transition:"slide",thumbCrop:"height",_toggleInfo:true},init:function(t){Galleria.requires(1.28,"This version of Classic theme requires Galleria 1.2.8 or later");this.addElement("info-link","info-close");this.append({info:["info-link","info-close"]});var e=this.$("info-link,info-close,info-text"),s=Galleria.TOUCH,n=s?"touchstart":"click";this.$("loader,counter").show().css("opacity",.4); [...]
\ No newline at end of file
diff --git a/doc/_static/galleria_index.css b/doc/_static/galleria_index.css
new file mode 100644
index 0000000..d9065b2
--- /dev/null
+++ b/doc/_static/galleria_index.css
@@ -0,0 +1,10 @@
+.galleria { margin:auto; } 
+.galleria-container { background: transparent; }
+.galleria-thumbnails {visibility:hidden;}
+.galleria-thumbnails-container {visibility:hidden; height:0px;}
+/*
+.galleria-image-nav-left {visibility:hidden;}
+.galleria-image-nav-right {visibility:hidden;}
+.galleria-thumb-nav-left {visibility:hidden;}
+.galleria-thumb-nav-right {visibility:hidden;}
+*/
\ No newline at end of file
diff --git a/doc/_static/galleria_index.js b/doc/_static/galleria_index.js
new file mode 100644
index 0000000..61a0999
--- /dev/null
+++ b/doc/_static/galleria_index.js
@@ -0,0 +1,14 @@
+config = {
+  dataSource: [
+    { image: "_static/banner1.png" },
+    { image: "_static/banner2.png" }, ],
+  transition: "fadeslide", // fade, flash, pulse, slide, fadeslide
+  transitionSpeed: 500,
+  autoplay: 3000,
+  thumbnails: false,
+  overlayBackground: "#FFFFFF",
+  showCounter: false,
+  showImagenav: true,
+  width: "90%",
+  height: 500,
+}
\ No newline at end of file
diff --git a/doc/_templates/index.html b/doc/_templates/index.html
index 35d2404..822d4cf 100644
--- a/doc/_templates/index.html
+++ b/doc/_templates/index.html
@@ -1,5 +1,11 @@
 {% extends "layout.html" %}
 {% set title = 'PyTango documentation' %}
+{% set script_files = script_files + ["_static/galleria/galleria-1.3.2.js",
+                                      "_static/galleria_index.js",
+                                      "_static/galleria/themes/classic/galleria.classic.min.js"] %}
+{% set css_files = css_files + ["_static/galleria/themes/classic/galleria.classic.css",
+                                "_static/galleria_index.css"] %}
+
 {% block body %}
 
 <h1>Welcome to PyTango documentation!</h1>
@@ -12,94 +18,18 @@
   of this in pure python.
 </p>
 
-<div class="figure align-center">
-<img alt="ITango" src="_static/banner.png" style="width: 70%;" />
-</div>
+<div class="galleria"/>
+
+<script>
+  Galleria.run(".galleria", config);
+</script>
 
 <p>
     Check out the <a class="reference internal" href="start.html#getting-started"><em>getting started guide</em></a>
     to learn how to build and/or install PyTango and after that the <a class="reference internal" href="quicktour.html#quick-tour"><em>quick tour</em></a>
     can help you with the first steps in the PyTango world.
-    In the meantime here is a preview:
 </p>
 
-<table><tbody>
-<tr>
-  <td rowspan="2" style="width:50%; vertical-align:top;">
-
-<div class="highlight-python"><div class="highlight"><pre>
-<span class="c"># --------------- Server -------------------</span>
-
-<span class="kn">import</span> <span class="nn">time</span>
-
-<span class="kn">from</span> <span class="nn">PyTango</span> <span class="kn">import</span> <span class="n">server_run</span>
-<span class="kn">from</span> <span class="nn">PyTango.hlapi</span> <span class="kn">import</span> <span class="n">Device</span><span class="p">,</span> <span class="n">DeviceMeta</span>
-<span class="kn">from</span> <span class="nn">PyTango.hlapi</span> <span class="kn">import</span> <span class="n">attribute</span><span class="p">,</span> <span class="n">command</span>
-
-<span class="k">class</span> <span class="nc">Clock</span><span class="p">(</span><span class="n">Device</span><span class="p">):</span>
-    <span class="n">__metaclass__</span> <span class="o">=</span> <span class="n">DeviceMeta</span>
-
-    <span class="n">time</span> <span class="o">=</span> <span class="n">attribute</span><span class="p">()</span>
-
-    <span class="k">def</span> <span class="nf">read_time</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
-        <span class="k">return</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span>
-
-    <span class="nd">@command</span><span class="p">(</span><span class="n">din_type</span><span class="o">=</span><span class="nb">str</span><span class="p">,</span> <span class="n">dout_type</span><span class="o">=</span><span class="nb">str</span><span class="p">)</span>
-    <span class="k">def</span> <span class="nf">strftime</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">format</span><span class="p">):</span>
-        <span class="k">return</span> <span class="n">time</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="n">format</span><span class="p">)</span>
-
-<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">"__main__"</span><span class="p">:</span>
-    <span class="n">server_run</span><span class="p">((</span><span class="n">Clock</span><span class="p">,))</span>
-
-
-
-
-</pre></div></div>
-
-  </td>
-  <td style="width:50%; vertical-align:top;">
-
-<div class="highlight-python"><div class="highlight"><pre>
-<span class="n">$</span><span class="c"> # ---------- Python Client --------------</span>
-
-<span class="n">$ python</span>
-
-<span class="gp">>>> </span><span class="kn">from</span> <span class="nn">PyTango</span> <span class="kn">import</span> <span class="n">DeviceProxy</span>
-
-<span class="gp">>>> </span><span class="n">clock</span> <span class="o">=</span> <span class="n">DeviceProxy</span><span class="p">(</span><span class="s">"my/first/clock"</span><span class="p">)</span>
-
-<span class="gp">>>> </span><span class="n">clock</span><span class="o">.</span><span class="n">time</span>
-<span class="go">1384447223.774121</span>
-
-<span class="gp">>>> </span><span class="n">clock</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s">"%H:%M:%S"</span><span class="p">)</span>
-<span class="go">'17:41:50'</span>
-</pre></div></div>
-  </td>
-
-</tr>
-<tr><td>
-
-    <div class="highlight-python">
-      <div class="highlight">
-<pre>
-<span class="n">$</span><span class="c"> # -------- ITango Client ----------------</span>
-
-<span class="n">$ itango</span>
-
-<span class="gp">ITango [1]: </span><span class="n">clock</span> <span class="o">=</span> <span class="n">Clock</span><span class="p">(</span><span class="s">"my/first/clock"</span><span class="p">)</span>
-
-<span class="gp">ITango [2]: </span><span class="n">clock</span><span class="o">.</span><span class="n">time</span>
-<span class="go">1384447223.774121</span>
-
-<span class="gp">ITango [3]: </span><span class="n">clock</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s">"%H:%M:%S"</span><span class="p">)</span>
-<span class="go">'17:41:50'</span>
-</pre>
-      </div>
-    </div>
-
-</td></tr>
-</tbody></table>
-
 <p>
     If you need help understanding what Tango itself really is, you can check the
     <a class="reference external" href="http://www.tango-controls.org/">Tango</a>
diff --git a/doc/_templates/layout.html b/doc/_templates/layout.html
index cb4dc53..0e1e248 100644
--- a/doc/_templates/layout.html
+++ b/doc/_templates/layout.html
@@ -1,19 +1,6 @@
 {% extends "sphinxdoc/layout.html" %}
 
 {% block extrahead %}
-    <script src="{{ pathto('_static/js/jquery.min.js',1) }}"></script> 
-    <script src="{{ pathto('_static/js/jquery.mousewheel.min.js',1) }}"></script> 
-    <script src="{{ pathto('_static/js/jquery.terminal.min.js',1) }}"></script> 
-    <link href="{{ pathto('_static/css/jquery.terminal.css',1) }}" rel="stylesheet"/> 
-    
-    <link href="{{ pathto('_static/css/start/jquery-ui-1.8.10.custom.css',1) }}" rel="stylesheet"/> 
-    <link href="{{ pathto('_static/css/pytango.css',1) }}" rel="stylesheet"/> 
-    <link href="{{ pathto('_static/css/pytango_terminal.css',1) }}" rel="stylesheet"/> 
-    <script src="{{ pathto('_static/js/jquery-ui-1.8.10.custom.min.js',1) }}"></script> 
-    
-    <script src="{{ pathto('_static/js/dterm.js',1) }}"></script> 
-    <script src="{{ pathto('_static/js/pytango.js',1) }}"></script> 
-
 {% endblock %}
 
 {% block rootrellink %}
diff --git a/doc/conf.py b/doc/conf.py
index 145cc20..d911a31 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -49,12 +49,19 @@ master_doc = 'contents'
 
 # General information about the project.
 project = u'PyTango'
-copyright = u'2012, ALBA - CELLS'
 copyright = u"""Except where otherwise noted, content on this site is
 licensed under a Creative Commons Attribution 3.0 License"""
 
 #Ideally we would like to put the following html code for copyright... but how?
-'''<a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/es/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-sa/3.0/es/88x31.png" /></a><br /><span xmlns:dc="http://purl.org/dc/elements/1.1/" href="http://purl.org/dc/dcmitype/Text" property="dc:title" rel="dc:type">Tau Documentation</span> by <span xmlns:cc="http://creativecommons.org/ns#" property="cc:attributionName">CELLS - ALBA</span> is licensed under a <a rel="licens [...]
+'''\
+<a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/es/">
+  <img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-sa/3.0/es/88x31.png" />
+</a><br />
+<span xmlns:dc="http://purl.org/dc/elements/1.1/" href="http://purl.org/dc/dcmitype/Text" property="dc:title" rel="dc:type">PyTango Documentation</span>
+by
+<span xmlns:cc="http://creativecommons.org/ns#" property="cc:attributionName">ESRF</span>
+is licensed under a
+<a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/es/">Creative Commons Attribution-Share Alike 3.0 Spain License</a>.'''
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
diff --git a/doc/server/index.rst b/doc/server/index.rst
index 010645b..d437c04 100644
--- a/doc/server/index.rst
+++ b/doc/server/index.rst
@@ -755,7 +755,7 @@ Server API
 .. toctree::
     :maxdepth: 2
     
-    hlapi
+    server
     device
     device_class
     logging
diff --git a/doc/server/hlapi.rst b/doc/server/server.rst
similarity index 93%
rename from doc/server/hlapi.rst
rename to doc/server/server.rst
index ddabf83..782cd47 100644
--- a/doc/server/hlapi.rst
+++ b/doc/server/server.rst
@@ -1,5 +1,5 @@
 
-.. currentmodule:: PyTango.hlapi
+.. currentmodule:: PyTango.server
 
 .. _pytango-hlapi:
 
@@ -15,8 +15,8 @@ high level API::
     
     import time
     from PyTango import server_run
-    from PyTango.hlapi import Device, DeviceMeta
-    from PyTango.hlapi import attribute, command   
+    from PyTango.server import Device, DeviceMeta
+    from PyTango.server import attribute, command   
 
     class Clock(Device):
         __metaclass__ = DeviceMeta
@@ -49,8 +49,8 @@ high level API. The example contains:
     from time import time
 
     from PyTango import AttrQuality, AttrWriteType, DispLevel, server_run
-    from PyTango.hlapi import Device, DeviceMeta, attribute, command
-    from PyTango.hlapi import class_property, device_property
+    from PyTango.server import Device, DeviceMeta, attribute, command
+    from PyTango.server import class_property, device_property
 
     class PowerSupply(Device):
         __metaclass__ = DeviceMeta
@@ -179,8 +179,8 @@ Here is an example of a PowerSupply device with:
     from time import time
         
     from PyTango import AttrQuality, DebugIt, server_run
-    from PyTango.hlapi import Device, DeviceMeta
-    from PyTango.hlapi import attribute, command, device_property
+    from PyTango.server import Device, DeviceMeta
+    from PyTango.server import attribute, command, device_property
 
     class PowerSupply(Device):
         __metaclass__ = DeviceMeta
@@ -298,17 +298,19 @@ And here is the equivalent code using the low-level API:
 API
 ---
 
-.. automodule:: PyTango.hlapi
+.. automodule:: PyTango.server
 
    .. autoclass:: Device
       :show-inheritance:
       :inherited-members:
       :members:
 
-   .. autofunction:: attribute
+   .. autoclass:: attribute
 
    .. autofunction:: command
 
-   .. autofunction:: device_property
+   .. autoclass:: device_property
 
-   .. autofunction:: class_property
+   .. autoclass:: class_property
+
+   .. autofunction:: server_run
diff --git a/doc/utilities.rst b/doc/utilities.rst
index 27caf33..26152c9 100644
--- a/doc/utilities.rst
+++ b/doc/utilities.rst
@@ -3,8 +3,6 @@
 The Utilities API
 =================
 
-.. autofunction:: PyTango.server_run
-
 .. currentmodule:: PyTango.utils
 
 .. autoclass:: PyTango.utils.EventCallBack

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/pytango.git



More information about the debian-science-commits mailing list