﻿
function handleKeyPress(e, form) {
    var evt = e ? e : window.event;
    if (evt.keyCode == 13) {
        CreateAWord();
        return false;
    } else {
        if (!isAlpha(evt)) {
            return false;
        }
    }
}
function Clear(id) {document.getElementById(id).innerHTML = '';}
function ShowDiv(divid) {document.getElementById(divid).style.display = 'block'; }
function HideDiv(divid) { document.getElementById(divid).style.display = 'none'; ; }
function setFocus(e){document.getElementById(e).focus(); }
function isAlpha(evt) {
    var keyCode = evt.which ? evt.which : evt.keyCode;
    alpha = (keyCode >= 'a'.charCodeAt() &&
    keyCode <= 'z'.charCodeAt()) ||
    (keyCode >= 'A'.charCodeAt() &&
    keyCode <= 'Z'.charCodeAt()) ||
    (keyCode >= 8 && keyCode <= 46);
    return (alpha);
}
function popup(h, w, ref) {
    var iMyWidth, iMyHeight, win2;
    iMyWidth = (window.screen.width / 2) - ((w / 2));
    iMyHeight = (window.screen.height / 2) - ((h / 2));
    win2 = window.open(ref, "Window2", "status=no,height=" + h + ",width=" + w + ",resizable=yes,left=" + iMyWidth + ",top=" + iMyHeight + ",screenX=" + iMyWidth + ",screenY=" + iMyHeight + ",toolbar=no,menubar=no,scrollbars=no,location=no,directories=no");
    win2.focus();
}
function timedMsg(id) {var t = setTimeout(function() { Clear(id) }, 3000)}
function timedMsg2(id, message) {var t = setTimeout(function() { showMessage2(id, message) }, 1000)}
function ToggleDiv(a) {
    var d = document.getElementById(a);
    if (d.style.display == 'block'){d.style.display = 'none';}else{d.style.display = 'block';}
}

/*--Shopping Basket --*/
function AddToBasket(itemID, divOfLabel, updatebasket) {
    var q = 1
    if (document.getElementById('txtRetailQuantity_' + itemID)) {
        q = document.getElementById('txtRetailQuantity_' + itemID).value;
        if (q) {} else {q = 1}
    }
    var datatopost = 'fn=AddToBasket&apid=' + apid + '&iid=' + itemID + '&q=' + q;
    var divid = 'shoppingbasketitems';

    SendDataAndChangeDivContentsNonAsync(page, datatopost, divOfLabel);

    var div = document.getElementById(divOfLabel);
    div.innerHTML = '<span style="color:green;font-weight:bold;">Item added to cart!</span>';
    timedMsg(divOfLabel);
    UB();
    loc();
}
function loc() { window.location = 'basket.aspx'; }
function AddToBasketFromCreateAWord(itemID) {
    var datatopost = 'fn=AddToBasket&apid=' + apid + '&iid=' + itemID;
    SendDataNonAsync(page, datatopost);
}
function AddFrameToBasket(itemID, divOfLabel) {
    var quantity = 1;
    var msg;
    var ddl = document.getElementById('ddlFrameOpening');
    var div = document.getElementById(divOfLabel);
    var num = 0
    if (ddl) {
        if (ddl.selectedIndex == 0) {
            msg = '<span style="color:red;font-weight:bold;">Please select a frame opening.</span>';
        } else {
            num = ddl.options[ddl.selectedIndex].value;
            itemID = itemID + num
            msg = '<span style="color:green;font-weight:bold;">Item added to cart. </span>';
            var datatopost = 'fn=AddToBasket&apid=' + apid + '&iid=' + itemID + '&q=' + quantity;
            SendDataAndChangeDivContentsNonAsync(page, datatopost, divOfLabel);
            UB();
        }
        div.innerHTML = msg;
        timedMsg(divOfLabel);
    }
    loc();
}
function AddFramedWordToCart() {
    var FormEdit = document.getElementById('aspnetForm'); 
    var letters, lettersCount, frameid, addAFrameResult;
    var div = document.getElementById('addLettersFromWordResult');

    div.innerHTML = '<div style="text-align: center; "><br /><br /><img src="images/loading.gif" alt="loading" /><br /><br /><p>Loading - Please wait</p></div>'
    //1. Initialise variables
    letters = '';
    lettersCount = 0;
    //2. Loop through letters and add the ID's of letters to save
    var tag = document.getElementsByTagName('input');
    for (x = 0; x < tag.length; x++) {
        var name = tag[x].name
        var val = tag[x].value;
        if (name.indexOf('hdn_letter_') != -1) {
            letters = (letters + val + ',');
            lettersCount = lettersCount + 1;
        }
    }
    //3. ensure the letters used are formatted correctly.
    if (letters.length > 0) { letters = letters.substring(0, letters.length - 1); } //remove last commar
    else { letters = ''; } //otherwise set letters to default
    //4. Get frame
    var frameid = document.getElementById('hdn_frame').value;
    var word = document.getElementById('ctl00_ContentPlaceHolder1_hdnWord').value;
    //alert(word);
    //5. Check for errors
    var addAFrameResult = AddFramedWord(apid, letters, lettersCount, frameid, word);
    //timedMsg2('addLettersFromWordResult', '<span style="color:green;font-weight:bold;">Completed!</span>')
    //UB();
    loc();
}
function AddLettersFromWordToCart(currentpage) {
    var div = document.getElementById('addLettersFromWordResult');
    div.innerHTML = '<div style="text-align: center; "><br /><br /><img src="images/loading.gif" alt="loading" /><br /><br /><p>Loading - Please wait</p></div>'
    var tag = document.getElementsByTagName('input');
    for (x = 0; x < tag.length; x++) {
        var name = tag[x].name
        if (name.indexOf('hdn_letter_') != -1) {
            AddToBasketFromCreateAWord(tag[x].value)
        }
    }
    loc();
}
function AddFramedWord(apid, letters, lettersCount, fid, word) {
   // var datatopost = ;
    var msg = SendDataNonAsync(page, 'fn=AddFramedWordToCart&apid=' + apid + '&l=' + letters + '&lc=' + lettersCount + '&fid=' + fid + '&w=' + word);
    return msg;
}
function CancelUpdateQuantity(itemid, currentpage) {
    UB();
}
function CancelUpdateShipping(currentpage) {
    UB();
}
function Clear(id) {
    var div = document.getElementById(id);
    div.innerHTML = '';
}
function ClearBasket(currentpage) {
    var datatopost = 'fn=ClearBasket&apid=' + apid;
    SendDataNonAsync(page, datatopost);
    UB();
}
function ClearTotals() {
    var t = document.getElementById("hdnTotalAmount");
    var s = document.getElementById("hdnShippingAmount");
    t.value = 0;
    s.value = 0;
}
function DisplayBasketHeader(currentpage) {
    var datatopost = 'fn=DisplayBasketHeader&apid=' + apid + '&currentpage=' + currentpage;
    var divid = 'headerBasketContents';
    SendDataAndChangeDivContents(page, datatopost, divid);
}
function DisplayCheckoutBasket(currentpage) {
    var datatopost = 'fn=DisplayBasketHeader&apid=' + apid + '&currentpage=' + currentpage;
    var divid = 'checkoutBasketContents';
    SendDataAndChangeDivContents(page, datatopost, divid);
}
function DownloadAlpahbetizeMeImage() {

    var letters;
    var lettersCount;
    var word;
    letters = '';
    lettersCount = 0;
    word = '';
    //2. Loop through letters and add the ID's of letters to save
    var tag = document.getElementsByTagName('input');
    for (x = 0; x < tag.length; x++) {
        var name = tag[x].name
        var val = tag[x].value;
        if (name.indexOf('hdn_letter_') != -1) {
            letters = (letters + val + '|');
            lettersCount = lettersCount + 1;
            word = word + val.substring(0, 1);
        }
    }
    if (letters.length > 0) {
        letters = letters.substring(0, letters.length - 1); //remove last commar
    }
    else {
        letters = ''; //otherwise set letters to default
    }

    _gaq.push(['_trackEvent', 'AlphabetizeMe', 'Downloaded', '']);
    window.location = 'alphabetize_me.aspx?fn=download&l=' + letters + '&w=' + word;
}
function EditQuantity(itemid) {
    HideDiv('qty_' + itemid);
    HideDiv('delete_' + itemid);
    ShowDiv('qty_' + itemid + '_edit');
    ShowDiv('qty_' + itemid + '_editYesNo');
}
function GetBasketItemTotal(currentpage) {
    var datatopost = 'fn=GetBasketItemTotal&apid=' + apid;
    var divid = 'body-head-top';
    SendDataAndChangeDivContents(page, datatopost, divid);
}
function ProcessPromotionCode(currentpage) {
    var t = document.getElementById("txtPromotionCodeShoppingBasket");
    var datatopost = 'fn=RedeemPC&apid=' + apid + '&currentpage=' + currentpage + '&c=' + t.value;
    var divid = 'divPromotionCodeLabel';
    var response = SendDataNonAsync(page, datatopost);
    if (response != '') {
        document.getElementById(divid).innerHTML = response;
    } else {
        document.getElementById(divid).innerHTML = 'Successful!';
        UB();
    }
}
function RemoveFromBasket(itemID, currentpage) {
    var datatopost = 'fn=RemoveFromBasket&apid=' + apid + '&iid=' + itemID;
    SendDataNonAsync(page, datatopost);
    UB();
}
function ShowHideShipping(divid) {
    var div = document.getElementById(divid);
    if (div.style.display == 'block') {
        HideDiv(divid);
    } else {
        ShowDiv(divid);
    }
}
function showMessage(id, message) {
    var div = document.getElementById(id);
    div.innerHTML = message;
}
function showMessage2(id, message) {
    var div = document.getElementById(id);
    div.innerHTML = message;
}
function UB() {
    if (document.getElementById('body-head-top')) {
        GetBasketItemTotal('body-head-top');
    }
}

function UpdateQuantity(itemid) {
    var q = document.getElementById('txtQuantity_' + itemid).value;
    var datatopost = 'fn=UpdateQuantity&apid=' + apid + '&iid=' + itemid + '&q=' + q;
    SendDataNonAsync(page, datatopost);
    UB();
}
function UpdateShipping(currentpage) {
    var q = document.getElementsByName('shippingOptions');
    var s;
    for (i = 0; i < document.getElementsByTagName('input').length; i++) {
        if (document.getElementsByTagName('input')[i].type == 'radio') {

            var ship = document.getElementsByTagName('input')[i]
            if (ship.checked == true) {
                s = ship.value;
            }
        }
    }
    var datatopost = 'fn=UpdateShipping&apid=' + apid + '&s=' + s;
    SendDataNonAsync(page, datatopost);
    UB();
}      
/*--Ajax functions --*/
// ### Instantiate XMLHTTP Object - cross browser (new IE / new Mozilla)
var xmlhttp
var xmlhttp = null;
xmlhttp = createXMLHttp();

function createXMLHttp() {
    if (window.XMLHttpRequest) {
        return new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        var aVersions = ["Microsoft.XMLHttp", "MSXML2.XMLHttp", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp.4.0", "MSXML2.XMLHttp.5.0"];

        for (var i = 0; i < aVersions.length; i++) {
            try {
                var oXmlHttp = new ActiveXObject(aVersions[i]);

                return oXmlHttp;
            } catch (oError) {
                //Do nothing
            }
        }
    }
    throw new Error("XMLHttp object could be created.");
}

function SendDataAndChangeDivContents(page, datatopost, divid) {

    var httpreq = null;
    httpreq = createXMLHttp();
    httpreq.onreadystatechange = function() {
        if (httpreq.readyState == 1) {
            var div = document.getElementById(divid);
            div.innerHTML = 'Loading - Please wait...';
        }

        if (httpreq.readyState == 4) {
            datareturned = httpreq.responseText;
            var div = document.getElementById(divid);
            div.innerHTML = datareturned;
        }
    };
    httpreq.open("POST", page, true);
    httpreq.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;");
    httpreq.send(datatopost);
}

function SendDataAndChangeDivContentsNonAsync(page, datatopost, divid) {
    xmlhttp.open("POST", page, false);
    xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;");
    xmlhttp.send(datatopost);
    if (xmlhttp.status == 200) {
        datareturned = xmlhttp.responseText;
        var div = document.getElementById(divid);
        div.innerHTML = datareturned;
    }
}
function SendDataNonAsync(page, datatopost) {
    xmlhttp.open('POST', page, false);
    xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
    xmlhttp.send(datatopost);
    return xmlhttp.responseText;
}
function SendDataNonAsyncAndChangeDiv(page, datatopost, divid) {
    xmlhttp.open('POST', page, false);
    xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
    xmlhttp.send(datatopost);
    document.getElementById(divid).innerHTML = xmlhttp.responseText;
}

/*--Create a word --*/
function CreateAWord() {
    var word = document.getElementById('ctl00_ContentPlaceHolder1_txtWord').value;
    document.getElementById('ctl00_ContentPlaceHolder1_hdnWord').value = word;
    var datatopost = 'fn=CreateAWord&apid=' + apid + '&word=' + word + '&frameid=1';
    var divid = 'searchResults';
    SendDataAndChangeDivContents(page, datatopost, divid);
    HideDiv('FilterLetters');
    HideDiv('AddAFrame');
    ShowDiv('searchResults');
    //_gaq.push(['_trackEvent', 'CreateAWord', 'CreatedWord', '']);
}

function AlphabetizeMe(l, w) {
    if (l && l.length > 0) {
        // 1. We can build the word from letters passed in.
        var datatopost = 'fn=CreateAWord&apid=' + apid + '&letters=' + l + '&word=' + w + '&frameid=0' + '&ab_me=Y' + '&category=SIGNS';
        document.getElementById('ctl00_ContentPlaceHolder1_txtWord').value = w;
    } else {
        //2. We can either build a word from the textbox
        var word = document.getElementById('ctl00_ContentPlaceHolder1_txtWord').value;
        document.getElementById('ctl00_ContentPlaceHolder1_hdnWord').value = word;
        var datatopost = 'fn=CreateAWord&apid=' + apid + '&word=' + word + '&frameid=0' + '&ab_me=Y' + '&category=SIGNS';
    }
    
    var divid = 'searchResults';
    SendDataAndChangeDivContents(page, datatopost, divid);
   
    HideDiv('FilterLetters');
    HideDiv('AddAFrame');
    ShowDiv('searchResults');
    ShowDiv('SocalNetworks');
    //Google track event.
    _gaq.push(['_trackEvent', 'AlphabetizeMe', 'CreatedWord', '']);

}
function AlphabetizeMeFromSBFID(sbf_apid, sbf_sbfid, frameid) {
    var datatopost = 'fn=CreateAWord&apid=' + sbf_apid + '&sbfid=' + sbf_sbfid + '&frameid=' + frameid + '&ab_me=Y' + '&category=SIGNS';
    var divid = 'searchResults';
    SendDataAndChangeDivContents(page, datatopost, divid);
    HideDiv('FilterLetters');
    HideDiv('AddAFrame');
    ShowDiv('searchResults');
    ShowDiv('SocalNetworks');
}

function CreateAWordFromSBFID(sbf_apid, sbf_sbfid, frameid) {
    var datatopost = 'fn=CreateAWord&apid=' + sbf_apid + '&sbfid=' + sbf_sbfid + '&frameid=' + frameid;
    var divid = 'searchResults';
    SendDataAndChangeDivContents(page, datatopost, divid);
    HideDiv('FilterLetters');
    HideDiv('AddAFrame');
    ShowDiv('searchResults');
}

function ReCreateAWord(frameid) {
    var tag = document.getElementsByTagName('input');
    var letters = '';
    for (x = 0; x < tag.length; x++) {
        var name = tag[x].name
        if (name.indexOf('hdn_letter_') != -1) {
            letters = letters + tag[x].value + '|';
        }
    }
    var datatopost = 'fn=CreateAWord&apid=' + apid + '&letters=' + letters + '&frameid=' + frameid;
    var divid = 'searchResults';
    SendDataAndChangeDivContents(page, datatopost, divid);
    HideDiv('FilterLetters');
    HideDiv('AddAFrame');
    ShowDiv('searchResults');
}
function CreateWordFromSFID(word_apid, sfid, frameid) {
    var datatopost = 'fn=CreateAWord&word_apid=' + word_apid + '&sfid=' + sfid + '&frameid=' + frameid;
    var divid = 'searchResults';
    SendDataAndChangeDivContents(page, datatopost, divid);
    HideDiv('FilterLetters');
    ShowDiv('searchResults');
}
function ShowLetters(letter, div, h, w, s, hid) {
    var datatopost = 'fn=GetLettersForCreateAWord&apid=' + apid + '&letter=' + letter + '&h=' + h + '&w=' + w + '&div=' + div + '&s=' + s + '&hid=' + hid;
    var divid = 'FilterLetters';
    SendDataAndChangeDivContentsNonAsync(page, datatopost, divid);
    HideDiv('searchResults');
    ShowDiv('FilterLetters');
}
function ShowLettersAB(letter, div, h, w, s, hid) {
    var datatopost = 'fn=GetLettersForCreateAWord&apid=' + apid + '&letter=' + letter + '&h=' + h + '&w=' + w + '&div=' + div + '&s=' + s + '&hid=' + hid + '&category=SIGNS' + '&ab_me=Y';
    var divid = 'FilterLetters';
    SendDataAndChangeDivContentsNonAsync(page, datatopost, divid);
    HideDiv('searchResults');
    ShowDiv('FilterLetters');
}
function CloseFilterLetter() {
    HideDiv('FilterLetters');
    ShowDiv('searchResults');
}
function ChangeALetter(letter, item_id, newimage, divtochange, h, w, s, hid) {
    var ahref = '<a href="javascript:ShowLetters(\'' + letter + '\', \'' + divtochange + '\',' + h + ',' + w + ',' + s + ',\'' + hid + '\')">'
    var hid = document.getElementById(hid);
    hid.value = item_id
    var div = document.getElementById(divtochange);
    div.innerHTML = ahref + '<img style="width:' + w + 'px;height:' + h + 'px; margin-right:' + s + 'px;" src="/images/medium/' + newimage + '" class="imgCreateAWord" /></a>'
    HideDiv('FilterLetters');
    ShowDiv('searchResults');
}
function ChangeALetterAB(letter, item_id, newimage, divtochange, h, w, s, hid) {
    var ahref = '<a href="javascript:ShowLettersAB(\'' + letter + '\', \'' + divtochange + '\',' + h + ',' + w + ',' + s + ',\'' + hid + '\')">'
    var hid = document.getElementById(hid);
    hid.value = item_id
    var div = document.getElementById(divtochange);
    div.innerHTML = ahref + '<img style="width:' + w + 'px;height:' + h + 'px; margin-right:' + s + 'px;" src="/images/ab_me/' + newimage + '" class="imgCreateAWord" /></a>'
    HideDiv('FilterLetters');
    ShowDiv('searchResults');
}
function AddAFrame(num) {
    var datatopost = 'fn=AddAFrame&apid=' + apid + '&n=' + num
    var divid = 'AddAFrame';
    SendDataAndChangeDivContentsNonAsync(page, datatopost, divid);
    HideDiv('searchResults');
    ShowDiv('AddAFrame');
    if (framing) {
        framing = true;
    }
}
function CloseAddAFrame() {
    HideDiv('AddAFrame');
    ShowDiv('searchResults');
}
function RemoveFrame() {
    ReCreateAWord(0)
    if (framing) {
        framing = false;
    }
}
function OpenSendToAFriendDiv() {
    ToggleDiv('sendToAFriendForm');
    var divValMsg = document.getElementById('sendToAFriendValidationMessage');
    divValMsg.innerHTML = ''
}
function SendWordToAFriend() {
    var FormEdit = document.getElementById('aspnetForm');
    var divLoadingMsg = document.getElementById('sendToAFriendLoadingMessage');
    var divValMsg = document.getElementById('sendToAFriendValidationMessage');
    var divForm = document.getElementById('sendToAFriendForm');
    var letters;
    var lettersCount;
    var sendToAFriendResult;
    var frameid;

    //Initialise variables
    letters = '';
    lettersCount = 0;
    //1. Show/Hide screens
    ShowDiv('sendToAFriendLoadingMessage');
    HideDiv('sendToAFriendForm');
    //2. Loop through letters and add the ID's of letters to save
    var tag = document.getElementsByTagName('input');
    for (x = 0; x < tag.length; x++) {
        var name = tag[x].name
        var val = tag[x].value;
        if (name.indexOf('hdn_letter_') != -1) {
            letters = (letters + val + ',');
            lettersCount = lettersCount + 1;
        }
    }

    //3. ensure the letters used are formatted correctly.
    if (letters.length > 0) {
        letters = letters.substring(0, letters.length - 1); //remove last commar
    }
    else {
        letters = ''; //otherwise set letters to default
    }
    //4A. Validate credentials
    var txtYourName = document.getElementById('txtYourName');
    var txtYourEmail = document.getElementById('txtYourEmail');
    var txtFriendsName = document.getElementById('txtFriendsName');
    var txtFriendsEmail = document.getElementById('txtFriendsEmail');

    //4B. Frame
    if (document.getElementById('hdn_frame')) {
        frameid = document.getElementById('hdn_frame').value;
    } else {
        frameid = 0;
    }
    //5. Check for errors
    var sendToFriendResult = SendToFriend(apid, letters, lettersCount, txtYourName.value, txtYourEmail.value, txtFriendsName.value, txtFriendsEmail.value, frameid)
    if (sendToFriendResult == 'SUCCESS') {
        divValMsg.innerHTML = '<span style="color:green;font-weight:bold;">Your message to ' + txtFriendsName.value + ' was successfully sent!</span>'
        // 6. Clear form
        txtYourName.value = ''
        txtYourEmail.value = ''
        txtFriendsName.value = ''
        txtFriendsEmail.value = ''
    } else {
        divValMsg.innerHTML = '<span style="color:red;font-weight:bold;">' + sendToFriendResult + '</span>'
    }
    //7. Show/Hide screens
    ShowDiv('sendToAFriendValidationMessage');
    ShowDiv('sendToAFriendForm');
    HideDiv('sendToAFriendLoadingMessage');
}
function SendToFriend(apid, letters, lettersCount, yn, ye, frn, fre, fid) {
    var datatopost = 'fn=SendToAFriend&apid=' + apid + '&l=' + letters + '&yn=' + yn + '&ye=' + ye + '&frn=' + frn + '&fre=' + fre + '&lc=' + lettersCount + '&fid=' + fid;
    var msg = SendDataNonAsync(page, datatopost);
    return msg;
}
/*--Default Button --*/
function clickDefaultButton(e, buttonid) {
    var evt = e ? e : window.event;
    var btn = document.getElementById(buttonid);
    if (btn) {
        if (evt.keyCode == 13) {
            btn.click();
            return false;
        }
    }
}

// ###### GALLERY SLID ##########

/*!
* Galleria v 1.1.95 2010-08-06
* http://galleria.aino.se
*
* Copyright (c) 2010, Aino
* Licensed under the MIT license.
*/

(function () {

    var initializing = false,
    fnTest = /xyz/.test(function () { xyz; }) ? /\b__super\b/ : /.*/,
    Class = function () { },
    window = this;

    Class.extend = function (prop) {
        var __super = this.prototype;
        initializing = true;
        var proto = new this();
        initializing = false;
        for (var name in prop) {
            if (name) {
                proto[name] = typeof prop[name] == "function" &&
                typeof __super[name] == "function" && fnTest.test(prop[name]) ?
                (function (name, fn) {
                    return function () {
                        var tmp = this.__super;
                        this.__super = __super[name];
                        var ret = fn.apply(this, arguments);
                        this.__super = tmp;
                        return ret;
                    };
                })(name, prop[name]) : prop[name];
            }
        }

        function Class() {
            if (!initializing && this.__constructor) {
                this.__constructor.apply(this, arguments);
            }
        }
        Class.prototype = proto;
        Class.constructor = Class;
        Class.extend = arguments.callee;
        return Class;
    };

    var Base = Class.extend({
        loop: function (elem, fn) {
            var scope = this;
            if (typeof elem == 'number') {
                elem = new Array(elem);
            }
            jQuery.each(elem, function () {
                fn.call(scope, arguments[1], arguments[0]);
            });
            return elem;
        },
        create: function (elem, className) {
            elem = elem || 'div';
            var el = document.createElement(elem);
            if (className) {
                el.className = className;
            }
            return el;
        },
        getElements: function (selector) {
            var elems = {};
            this.loop(jQuery(selector), this.proxy(function (elem) {
                this.push(elem, elems);
            }));
            return elems;
        },
        setStyle: function (elem, css) {
            jQuery(elem).css(css);
            return this;
        },
        getStyle: function (elem, styleProp, parse) {
            var val = jQuery(elem).css(styleProp);
            return parse ? this.parseValue(val) : val;
        },
        cssText: function (string) {
            var style = document.createElement('style');
            this.getElements('head')[0].appendChild(style);
            if (style.styleSheet) { // IE
                style.styleSheet.cssText = string;
            } else {
                var cssText = document.createTextNode(string);
                style.appendChild(cssText);
            }
            return this;
        },
        touch: function (el) {
            var sibling = el.nextSibling;
            var parent = el.parentNode;
            parent.removeChild(el);
            if (sibling) {
                parent.insertBefore(el, sibling);
            } else {
                parent.appendChild(el);
            }
            if (el.styleSheet && el.styleSheet.imports.length) {
                this.loop(el.styleSheet.imports, function (i) {
                    el.styleSheet.addImport(i.href);
                });
            }
        },
        loadCSS: function (href, callback) {
            var exists = this.getElements('link[href="' + href + '"]').length;
            if (exists) {
                callback.call(null);
                return exists[0];
            }
            var link = this.create('link');
            link.rel = 'stylesheet';
            link.href = href;

            if (typeof callback == 'function') {
                // a new css check method, still experimental...
                this.wait(function () {
                    return !!document.body;
                }, function () {
                    var testElem = this.create('div', 'galleria-container galleria-stage');
                    this.moveOut(testElem);
                    document.body.appendChild(testElem);
                    var getStyles = this.proxy(function () {
                        var str = '';
                        var props;
                        if (document.defaultView && document.defaultView.getComputedStyle) {
                            props = document.defaultView.getComputedStyle(testElem, "");
                            this.loop(props, function (prop) {
                                str += prop + props.getPropertyValue(prop);
                            });
                        } else if (testElem.currentStyle) { // IE
                            props = testElem.currentStyle;
                            this.loop(props, function (val, prop) {
                                str += prop + val;
                            });
                        }
                        return str;
                    });
                    var current = getStyles();
                    this.wait(function () {
                        return getStyles() !== current;
                    }, function () {
                        document.body.removeChild(testElem);
                        callback.call(link);
                    }, function () {
                        G.raise('Could not confirm theme CSS');
                    }, 2000);
                });
            }
            window.setTimeout(this.proxy(function () {
                var styles = this.getElements('link[rel="stylesheet"],style');
                if (styles.length) {
                    styles[0].parentNode.insertBefore(link, styles[0]);
                } else {
                    this.getElements('head')[0].appendChild(link);
                }
                // IE needs a manual touch to re-order the cascade
                if (G.IE) {
                    this.loop(styles, function (el) {
                        this.touch(el);
                    })
                }
            }), 2);
            return link;
        },
        moveOut: function (elem) {
            return this.setStyle(elem, {
                position: 'absolute',
                left: '-10000px',
                display: 'block'
            });
        },
        moveIn: function (elem) {
            return this.setStyle(elem, {
                left: '0'
            });
        },
        reveal: function (elem) {
            return jQuery(elem).show();
        },
        hide: function (elem) {
            return jQuery(elem).hide();
        },
        mix: function () {
            return jQuery.extend.apply(jQuery, arguments);
        },
        proxy: function (fn, scope) {
            if (typeof fn !== 'function') {
                return function () { };
            }
            scope = scope || this;
            return function () {
                return fn.apply(scope, Array.prototype.slice.call(arguments));
            };
        },
        listen: function (elem, type, fn) {
            jQuery(elem).bind(type, fn);
        },
        forget: function (elem, type, fn) {
            jQuery(elem).unbind(type, fn);
        },
        dispatch: function (elem, type) {
            jQuery(elem).trigger(type);
        },
        clone: function (elem, keepEvents) {
            keepEvents = keepEvents || false;
            return jQuery(elem).clone(keepEvents)[0];
        },
        removeAttr: function (elem, attributes) {
            this.loop(attributes.split(' '), function (attr) {
                jQuery(elem).removeAttr(attr);
            });
        },
        push: function (elem, obj) {
            if (typeof obj.length == 'undefined') {
                obj.length = 0;
            }
            Array.prototype.push.call(obj, elem);
            return elem;
        },
        width: function (elem, outer) {
            return this.meassure(elem, outer, 'Width');
        },
        height: function (elem, outer) {
            return this.meassure(elem, outer, 'Height');
        },
        meassure: function (el, outer, meassure) {
            var elem = jQuery(el);
            var ret = outer ? elem['outer' + meassure](true) : elem[meassure.toLowerCase()]();
            // fix quirks mode
            if (G.QUIRK) {
                var which = meassure == "Width" ? ["left", "right"] : ["top", "bottom"];
                this.loop(which, function (s) {
                    ret += elem.css('border-' + s + '-width').replace(/[^\d]/g, '') * 1;
                    ret += elem.css('padding-' + s).replace(/[^\d]/g, '') * 1;
                });
            }
            return ret;
        },
        toggleClass: function (elem, className, arg) {
            if (typeof arg !== 'undefined') {
                var fn = arg ? 'addClass' : 'removeClass';
                jQuery(elem)[fn](className);
                return this;
            }
            jQuery(elem).toggleClass(className);
            return this;
        },
        hideAll: function (el) {
            jQuery(el).find('*').hide();
        },
        animate: function (el, options) {
            options.complete = this.proxy(options.complete);
            var elem = jQuery(el);
            if (!elem.length) {
                return;
            }
            if (options.from) {
                elem.css(from);
            }
            elem.animate(options.to, {
                duration: options.duration || 400,
                complete: options.complete,
                easing: options.easing || 'swing'
            });
        },
        wait: function (fn, callback, err, max) {
            fn = this.proxy(fn);
            callback = this.proxy(callback);
            err = this.proxy(err);
            var ts = new Date().getTime() + (max || 3000);
            window.setTimeout(function () {
                if (fn()) {
                    callback();
                    return false;
                }
                if (new Date().getTime() >= ts) {
                    err();
                    callback();
                    return false;
                }
                window.setTimeout(arguments.callee, 2);
            }, 2);
            return this;
        },
        loadScript: function (url, callback) {
            var script = document.createElement('script');
            script.src = url;
            script.async = true; // HTML5

            var done = false;
            var scope = this;

            // Attach handlers for all browsers
            script.onload = script.onreadystatechange = function () {
                if (!done && (!this.readyState ||
               this.readyState == "loaded" || this.readyState == "complete")) {
                    done = true;

                    if (typeof callback == 'function') {
                        callback.call(scope, this);
                    }

                    // Handle memory leak in IE
                    script.onload = script.onreadystatechange = null;
                }
            };
            var s = document.getElementsByTagName('script')[0];
            s.parentNode.insertBefore(script, s);

            return this;
        },
        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;
            }
        }
    });

    var Picture = Base.extend({
        __constructor: function (order) {
            this.image = null;
            this.elem = this.create('div', 'galleria-image');
            this.setStyle(this.elem, {
                overflow: 'hidden',
                position: 'relative' // for IE Standards mode
            });
            this.order = order;
            this.orig = { w: 0, h: 0, r: 1 };
        },

        cache: {},
        ready: false,

        add: function (src) {
            if (this.cache[src]) {
                return this.cache[src];
            }
            var image = new Image();
            image.src = src;
            this.setStyle(image, { display: 'block' });
            if (image.complete && image.width) {
                this.cache[src] = image;
                return image;
            }
            image.onload = (function (scope) {
                return function () {
                    scope.cache[src] = image;
                };
            })(this);
            return image;
        },

        isCached: function (src) {
            return this.cache[src] ? this.cache[src].complete : false;
        },

        make: function (src) {
            var i = this.cache[src] || this.add(src);
            return this.clone(i);
        },

        load: function (src, callback) {
            callback = this.proxy(callback);
            this.elem.innerHTML = '';
            this.image = this.make(src);
            this.moveOut(this.image);
            this.elem.appendChild(this.image);
            this.wait(function () {
                return (this.image.complete && this.image.width);
            }, function () {
                this.orig = {
                    h: this.h || this.image.height,
                    w: this.w || this.image.width
                };
                callback({ target: this.image, scope: this });
            }, function () {
                G.raise('image not loaded in 20 seconds: ' + src);
            }, 20000);
            return this;
        },

        scale: function (options) {
            var o = this.mix({
                width: 0,
                height: 0,
                min: undefined,
                max: undefined,
                margin: 0,
                complete: function () { },
                position: 'center',
                crop: false
            }, options);
            if (!this.image) {
                return this;
            }
            var width, height;
            this.wait(function () {
                width = o.width || this.width(this.elem);
                height = o.height || this.height(this.elem);
                return width && height;
            }, function () {
                var nw = (width - o.margin * 2) / this.orig.w;
                var nh = (height - o.margin * 2) / this.orig.h;
                var rmap = {
                    'true': Math.max(nw, nh),
                    'width': nw,
                    'height': nh,
                    'false': Math.min(nw, nh)
                }
                var ratio = rmap[o.crop.toString()];
                if (o.max) {
                    ratio = Math.min(o.max, ratio);
                }
                if (o.min) {
                    ratio = Math.max(o.min, ratio);
                }
                this.setStyle(this.elem, {
                    width: width,
                    height: height
                });
                this.image.width = Math.ceil(this.orig.w * ratio);
                this.image.height = Math.ceil(this.orig.h * ratio);

                var getPosition = this.proxy(function (value, img, m) {
                    var result = 0;
                    if (/\%/.test(value)) {
                        var pos = parseInt(value) / 100;
                        result = Math.ceil(this.image[img] * -1 * pos + m * pos);
                    } else {
                        result = parseInt(value);
                    }
                    return result;
                });

                var map = {
                    'top': { top: 0 },
                    'left': { left: 0 },
                    'right': { left: '100%' },
                    'bottom': { top: '100%' }
                }

                var pos = {};
                var mix = {};

                this.loop(o.position.toLowerCase().split(' '), function (p, i) {
                    if (p == 'center') {
                        p = '50%';
                    }
                    pos[i ? 'top' : 'left'] = p;
                });

                this.loop(pos, function (val, key) {
                    if (map.hasOwnProperty(val)) {
                        mix = this.mix(mix, map[val]);
                    }
                });

                pos = pos.top ? this.mix(pos, mix) : mix;

                pos = this.mix({
                    top: '50%',
                    left: '50%'
                }, pos);

                this.setStyle(this.image, {
                    position: 'relative',
                    top: getPosition(pos.top, 'height', height),
                    left: getPosition(pos.left, 'width', width)
                });
                this.ready = true;
                o.complete.call(this);
            });
            return this;
        }
    });

    var G = window.Galleria = Base.extend({

        __constructor: function (options) {
            this.theme = undefined;
            this.options = options;
            this.playing = false;
            this.playtime = 5000;
            this.active = null;
            this.queue = {};
            this.data = {};
            this.dom = {};

            var kb = this.keyboard = {
                keys: {
                    UP: 38,
                    DOWN: 40,
                    LEFT: 37,
                    RIGHT: 39,
                    RETURN: 13,
                    ESCAPE: 27,
                    BACKSPACE: 8
                },
                map: {},
                bound: false,
                press: this.proxy(function (e) {
                    var key = e.keyCode || e.which;
                    if (kb.map[key] && typeof kb.map[key] == 'function') {
                        kb.map[key].call(this, e);
                    }
                }),
                attach: this.proxy(function (map) {
                    for (var i in map) {
                        var k = i.toUpperCase();
                        if (kb.keys[k]) {
                            kb.map[kb.keys[k]] = map[i];
                        }
                    }
                    if (!kb.bound) {
                        kb.bound = true;
                        this.listen(document, 'keydown', kb.press);
                    }
                }),
                detach: this.proxy(function () {
                    kb.bound = false;
                    this.forget(document, 'keydown', kb.press);
                })
            };

            this.timeouts = {
                trunk: {},
                add: function (id, fn, delay, loop) {
                    loop = loop || false;
                    this.clear(id);
                    if (loop) {
                        var self = this;
                        var old = fn;
                        fn = function () {
                            old();
                            self.add(id, fn, delay);
                        }
                    }
                    this.trunk[id] = window.setTimeout(fn, delay);
                },
                clear: function (id) {
                    if (id && this.trunk[id]) {
                        window.clearTimeout(this.trunk[id]);
                        delete this.trunk[id];
                    } else if (typeof id == 'undefined') {
                        for (var i in this.trunk) {
                            window.clearTimeout(this.trunk[i]);
                            delete this.trunk[i];
                        }
                    }
                }
            };

            this.controls = {
                0: null,
                1: null,
                active: 0,
                swap: function () {
                    this.active = this.active ? 0 : 1;
                },
                getActive: function () {
                    return this[this.active];
                },
                getNext: function () {
                    return this[Math.abs(this.active - 1)];
                }
            };

            var fs = this.fullscreen = {
                scrolled: 0,
                enter: this.proxy(function () {
                    this.toggleClass(this.get('container'), 'fullscreen');
                    fs.scrolled = jQuery(window).scrollTop();
                    this.loop(fs.getElements(), function (el, i) {
                        fs.styles[i] = el.getAttribute('style');
                        el.removeAttribute('style');
                    });
                    this.setStyle(fs.getElements(0), {
                        position: 'fixed',
                        top: 0,
                        left: 0,
                        width: '100%',
                        height: '100%',
                        zIndex: 10000
                    });
                    var bh = {
                        height: '100%',
                        overflow: 'hidden',
                        margin: 0,
                        padding: 0
                    };
                    this.setStyle(fs.getElements(1), bh);
                    this.setStyle(fs.getElements(2), bh);
                    this.attachKeyboard({
                        escape: this.exitFullscreen,
                        right: this.next,
                        left: this.prev
                    });
                    this.rescale(this.proxy(function () {
                        this.trigger(G.FULLSCREEN_ENTER);
                    }));
                    this.listen(window, 'resize', fs.scale);
                }),
                scale: this.proxy(function () {
                    this.rescale();
                }),
                exit: this.proxy(function () {
                    this.toggleClass(this.get('container'), 'fullscreen', false);
                    if (!fs.styles.length) {
                        return;
                    }
                    this.loop(fs.getElements(), function (el, i) {
                        el.removeAttribute('style');
                        el.setAttribute('style', fs.styles[i]);
                    });
                    window.scrollTo(0, fs.scrolled);
                    this.detachKeyboard();
                    this.rescale(this.proxy(function () {
                        this.trigger(G.FULLSCREEN_EXIT);
                    }));
                    this.forget(window, 'resize', fs.scale);
                }),
                styles: [],
                getElements: this.proxy(function (i) {
                    var elems = [this.get('container'), document.body, this.getElements('html')[0]];
                    return i ? elems[i] : elems;
                })
            };

            var idle = this.idle = {
                trunk: [],
                bound: false,
                add: this.proxy(function (elem, styles, fn) {
                    if (!elem) {
                        return;
                    }
                    if (!idle.bound) {
                        idle.addEvent();
                    }
                    elem = jQuery(elem);
                    var orig = {};
                    for (var style in styles) {
                        orig[style] = elem.css(style);
                    }
                    elem.data('idle', {
                        from: orig,
                        to: styles,
                        complete: true,
                        busy: false,
                        fn: this.proxy(fn)
                    });
                    idle.addTimer();
                    idle.trunk.push(elem);
                }),
                remove: this.proxy(function (elem) {
                    elem = jQuery(elem);
                    this.loop(idle.trunk, function (el, i) {
                        if (el && !el.not(elem).length) {
                            idle.show(elem);
                            idle.trunk.splice(i, 1);
                        }
                    });
                    if (!idle.trunk.length) {
                        idle.removeEvent();
                        this.clearTimer('idle');
                    }
                }),
                addEvent: this.proxy(function () {
                    idle.bound = true;
                    this.listen(this.get('container'), 'mousemove click', idle.showAll);
                }),
                removeEvent: this.proxy(function () {
                    idle.bound = false;
                    this.forget(this.get('container'), 'mousemove click', idle.showAll);
                }),
                addTimer: this.proxy(function () {
                    this.addTimer('idle', this.proxy(function () {
                        idle.hide();
                    }), this.options.idle_time);
                }),
                hide: this.proxy(function () {
                    this.trigger(G.IDLE_ENTER);
                    this.loop(idle.trunk, function (elem) {
                        var data = elem.data('idle');
                        data.complete = false;
                        data.fn();
                        elem.animate(data.to, {
                            duration: 600,
                            queue: false,
                            easing: 'swing'
                        });
                    });
                }),
                showAll: this.proxy(function () {
                    this.clearTimer('idle');
                    this.loop(idle.trunk, function (elem) {
                        idle.show(elem);
                    });
                }),
                show: this.proxy(function (elem) {
                    var data = elem.data('idle');
                    if (!data.busy && !data.complete) {
                        data.busy = true;
                        this.trigger(G.IDLE_EXIT);
                        elem.animate(data.from, {
                            duration: 300,
                            queue: false,
                            easing: 'swing',
                            complete: function () {
                                $(this).data('idle').busy = false;
                                $(this).data('idle').complete = true;
                            }
                        });
                    }
                    idle.addTimer();
                })
            };

            var lightbox = this.lightbox = {
                w: 0,
                h: 0,
                initialized: false,
                active: null,
                init: this.proxy(function () {
                    if (lightbox.initialized) {
                        return;
                    }
                    lightbox.initialized = true;
                    var elems = 'lightbox-overlay lightbox-box lightbox-content lightbox-shadow lightbox-title ' +
                            'lightbox-info lightbox-close lightbox-prev lightbox-next lightbox-counter';
                    this.loop(elems.split(' '), function (el) {
                        this.addElement(el);
                        lightbox[el.split('-')[1]] = this.get(el);
                    });

                    lightbox.image = new Galleria.Picture();

                    this.append({
                        'lightbox-box': ['lightbox-shadow', 'lightbox-content', 'lightbox-close'],
                        'lightbox-info': ['lightbox-title', 'lightbox-counter', 'lightbox-next', 'lightbox-prev'],
                        'lightbox-content': ['lightbox-info']
                    });
                    document.body.appendChild(lightbox.overlay);
                    document.body.appendChild(lightbox.box);
                    lightbox.content.appendChild(lightbox.image.elem);

                    lightbox.close.innerHTML = '&#215;';
                    lightbox.prev.innerHTML = '&#9668;';
                    lightbox.next.innerHTML = '&#9658;';

                    this.listen(lightbox.close, 'click', lightbox.hide);
                    this.listen(lightbox.overlay, 'click', lightbox.hide);
                    this.listen(lightbox.next, 'click', lightbox.showNext);
                    this.listen(lightbox.prev, 'click', lightbox.showPrev);

                    if (this.options.lightbox_clicknext) {
                        this.setStyle(lightbox.image.elem, { cursor: 'pointer' });
                        this.listen(lightbox.image.elem, 'click', lightbox.showNext);
                    }
                    this.setStyle(lightbox.overlay, {
                        position: 'fixed', display: 'none',
                        opacity: this.options.overlay_opacity,
                        top: 0, left: 0, width: '100%', height: '100%',
                        background: this.options.overlay_background, zIndex: 99990
                    });
                    this.setStyle(lightbox.box, {
                        position: 'fixed', display: 'none',
                        width: 400, height: 400, top: '50%', left: '50%',
                        marginTop: -200, marginLeft: -200, zIndex: 99991
                    });
                    this.setStyle(lightbox.shadow, {
                        background: '#000', opacity: .4, width: '100%', height: '100%', position: 'absolute'
                    });
                    this.setStyle(lightbox.content, {
                        backgroundColor: '#fff', position: 'absolute',
                        top: 10, left: 10, right: 10, bottom: 10, overflow: 'hidden'
                    });
                    this.setStyle(lightbox.info, {
                        color: '#444', fontSize: '11px', fontFamily: 'arial,sans-serif', height: 13, lineHeight: '13px',
                        position: 'absolute', bottom: 10, left: 10, right: 10, opacity: 0
                    });
                    this.setStyle(lightbox.close, {
                        background: '#fff', height: 20, width: 20, position: 'absolute', textAlign: 'center', cursor: 'pointer',
                        top: 10, right: 10, lineHeight: '22px', fontSize: '16px', fontFamily: 'arial,sans-serif', color: '#444', zIndex: 99999
                    });
                    this.setStyle(lightbox.image.elem, {
                        top: 10, left: 10, right: 10, bottom: 30, position: 'absolute'
                    });
                    this.loop('title prev next counter'.split(' '), function (el) {
                        var css = { display: 'inline', 'float': 'left' };
                        if (el != 'title') {
                            this.mix(css, { 'float': 'right' });
                            if (el != 'counter') {
                                this.mix(css, { cursor: 'pointer' });
                            } else {
                                this.mix(css, { marginLeft: 8 });
                            }
                        }
                        this.setStyle(lightbox[el], css);
                    });
                    this.loop('prev next close'.split(' '), function (el) {
                        this.listen(lightbox[el], 'mouseover', this.proxy(function () {
                            this.setStyle(lightbox[el], { color: '#000' });
                        }));
                        this.listen(lightbox[el], 'mouseout', this.proxy(function () {
                            this.setStyle(lightbox[el], { color: '#444' });
                        }));
                    });
                    this.trigger(G.LIGHTBOX_OPEN);
                }),
                rescale: this.proxy(function (e) {
                    var w = Math.min(this.width(window), lightbox.w);
                    var h = Math.min(this.height(window), lightbox.h);
                    var r = Math.min((w - 60) / lightbox.w, (h - 80) / lightbox.h);
                    var destW = (lightbox.w * r) + 40;
                    var destH = (lightbox.h * r) + 60;
                    var dest = {
                        width: destW,
                        height: destH,
                        marginTop: Math.ceil(destH / 2) * -1,
                        marginLeft: Math.ceil(destW) / 2 * -1
                    }
                    if (!e) {
                        this.animate(lightbox.box, {
                            to: dest,
                            duration: this.options.lightbox_transition_speed,
                            easing: 'galleria',
                            complete: function () {
                                this.trigger({
                                    type: G.LIGHTBOX_IMAGE,
                                    imageTarget: lightbox.image.image
                                });
                                this.moveIn(lightbox.image.image);
                                this.animate(lightbox.image.image, { to: { opacity: 1 }, duration: this.options.lightbox_fade_speed });
                                this.animate(lightbox.info, { to: { opacity: 1 }, duration: this.options.lightbox_fade_speed });
                            }
                        });
                    } else {
                        this.setStyle(lightbox.box, dest);
                    }
                }),
                hide: this.proxy(function () {
                    lightbox.image.image = null;
                    this.forget(window, 'resize', lightbox.rescale);
                    this.hide(lightbox.box);
                    this.setStyle(lightbox.info, { opacity: 0 });
                    this.animate(lightbox.overlay, {
                        to: { opacity: 0 },
                        duration: 200,
                        complete: function () {
                            this.hide(lightbox.overlay);
                            this.setStyle(lightbox.overlay, { opacity: this.options.overlay_opacity });
                            this.trigger(G.LIGHTBOX_CLOSE);
                        }
                    });
                }),
                showNext: this.proxy(function () {
                    lightbox.show(this.getNext(lightbox.active));
                }),
                showPrev: this.proxy(function () {
                    lightbox.show(this.getPrev(lightbox.active));
                }),
                show: this.proxy(function (index) {
                    if (!lightbox.initialized) {
                        lightbox.init();
                    }
                    this.forget(window, 'resize', lightbox.rescale);
                    index = typeof index == 'number' ? index : this.getIndex();
                    lightbox.active = index;

                    var data = this.getData(index);
                    var total = this.data.length;
                    this.setStyle(lightbox.info, { opacity: 0 });

                    lightbox.image.load(data.image, function (o) {
                        lightbox.w = o.scope.orig.w;
                        lightbox.h = o.scope.orig.h;
                        this.setStyle(o.target, {
                            width: '100.5%',
                            height: '100.5%',
                            top: 0,
                            zIndex: 99998,
                            opacity: 0
                        });
                        lightbox.title.innerHTML = data.title;
                        lightbox.counter.innerHTML = (index + 1) + ' / ' + total;
                        this.listen(window, 'resize', lightbox.rescale);
                        lightbox.rescale();
                    });
                    this.reveal(lightbox.overlay);
                    this.reveal(lightbox.box);
                })
            };

            this.thumbnails = { width: 0 };
            this.stageWidth = 0;
            this.stageHeight = 0;

            var elems = 'container stage images image-nav image-nav-left image-nav-right ' +
                    'info info-text info-title info-description info-author ' +
                    'thumbnails thumbnails-list thumbnails-container thumb-nav-left thumb-nav-right ' +
                    'loader counter';
            elems = elems.split(' ');

            this.loop(elems, function (blueprint) {
                this.dom[blueprint] = this.create('div', 'galleria-' + blueprint);
            });

            this.target = this.dom.target = options.target.nodeName ?
            options.target : this.getElements(options.target)[0];

            if (!this.target) {
                G.raise('Target not found.');
            }
        },

        init: function () {

            this.options = this.mix(G.theme.defaults, this.options);
            this.options = this.mix({
                autoplay: false,
                carousel: true,
                carousel_follow: true,
                carousel_speed: 400,
                carousel_steps: 'auto',
                clicknext: false,
                data_config: function (elem) { return {}; },
                data_image_selector: 'img',
                data_source: this.target,
                data_type: 'auto',
                debug: false,
                extend: function (options) { },
                height: 'auto',
                idle_time: 3000,
                image_crop: false,
                image_margin: 0,
                image_pan: false,
                image_pan_smoothness: 12,
                image_position: '50%',
                keep_source: false,
                lightbox_clicknext: true,
                lightbox_fade_speed: 200,
                lightbox_transition_speed: 300,
                link_source_images: true,
                max_scale_ratio: undefined,
                min_scale_ratio: undefined,
                on_image: function (img, thumb) { },
                overlay_opacity: .85,
                overlay_background: '#0b0b0b',
                popup_links: false,
                preload: 2,
                queue: true,
                show: 0,
                show_info: true,
                show_counter: true,
                show_imagenav: true,
                thumb_crop: true,
                thumb_fit: true,
                thumb_margin: 0,
                thumb_quality: 'auto',
                thumbnails: true,
                transition: G.transitions.fade,
                transition_speed: 400
            }, this.options);

            var o = this.options;

            this.bind(G.DATA, function () {
                this.run();
            });

            if (o.clicknext) {
                this.loop(this.data, function (data) {
                    delete data.link;
                });
                this.setStyle(this.get('stage'), { cursor: 'pointer' });
                this.listen(this.get('stage'), 'click', this.proxy(function () {
                    this.next();
                }));
            }

            this.bind(G.IMAGE, function (e) {
                o.on_image.call(this, e.imageTarget, e.thumbTarget);
            });

            this.bind(G.READY, function () {
                if (G.History) {
                    G.History.change(this.proxy(function (e) {
                        var val = parseInt(e.value.replace(/\//, ''));
                        if (isNaN(val)) {
                            window.history.go(-1);
                        } else {
                            this.show(val, undefined, true);
                        }
                    }));
                }

                G.theme.init.call(this, o);
                o.extend.call(this, o);

                if (/^[0-9]{1,4}$/.test(hash) && G.History) {
                    this.show(hash, undefined, true);
                } else if (typeof o.show == 'number') {
                    this.show(o.show);
                }

                if (o.autoplay) {
                    if (typeof o.autoplay == 'number') {
                        this.playtime = o.autoplay;
                    }
                    this.trigger(G.PLAY);
                    this.playing = true;
                }
            });
            this.load();
            return this;
        },

        bind: function (type, fn) {
            this.listen(this.get('container'), type, this.proxy(fn));
            return this;
        },

        unbind: function (type) {
            this.forget(this.get('container'), type);
        },

        trigger: function (type) {
            type = typeof type == 'object' ?
            this.mix(type, { scope: this }) :
            { type: type, scope: this };
            this.dispatch(this.get('container'), type);
            return this;
        },

        addIdleState: function () {
            this.idle.add.apply(this, arguments);
            return this;
        },

        removeIdleState: function () {
            this.idle.remove.apply(this, arguments);
            return this;
        },

        enterIdleMode: function () {
            this.idle.hide();
            return this;
        },

        exitIdleMode: function () {
            this.idle.show();
            return this;
        },

        addTimer: function () {
            this.timeouts.add.apply(this.timeouts, arguments);
            return this;
        },

        clearTimer: function () {
            this.timeouts.clear.apply(this.timeouts, arguments);
            return this;
        },

        enterFullscreen: function () {
            this.fullscreen.enter.apply(this, arguments);
            return this;
        },

        exitFullscreen: function () {
            this.fullscreen.exit.apply(this, arguments);
            return this;
        },

        openLightbox: function () {
            this.lightbox.show.apply(this, arguments);
        },

        closeLightbox: function () {
            this.lightbox.hide.apply(this, arguments);
        },

        getActive: function () {
            return this.controls.getActive();
        },

        getActiveImage: function () {
            return this.getActive().image || null;
        },

        run: function () {
            var o = this.options;
            if (!this.data.length) {
                G.raise('Data is empty.');
            }
            if (!o.keep_source && !Galleria.IE) {
                this.target.innerHTML = '';
            }
            this.loop(2, function () {
                var image = new Picture();
                this.setStyle(image.elem, {
                    position: 'absolute',
                    top: 0,
                    left: 0
                });
                this.setStyle(this.get('images'), {
                    position: 'relative',
                    top: 0,
                    left: 0,
                    width: '100%',
                    height: '100%'
                });
                this.get('images').appendChild(image.elem);
                this.push(image, this.controls);
            }, this);

            if (o.carousel) {
                // try the carousel on each thumb load
                this.bind(G.THUMBNAIL, this.parseCarousel);
            }

            this.build();
            this.target.appendChild(this.get('container'));

            this.loop(['info', 'counter', 'image-nav'], function (el) {
                if (o['show_' + el.replace(/-/, '')] === false) {
                    this.moveOut(this.get(el));
                }
            });

            var w = 0;
            var h = 0;

            for (var i = 0; this.data[i]; i++) {
                var thumb;
                if (o.thumbnails === true) {
                    thumb = new Picture(i);
                    var src = this.data[i].thumb || this.data[i].image;

                    this.get('thumbnails').appendChild(thumb.elem);

                    w = this.getStyle(thumb.elem, 'width', true);
                    h = this.getStyle(thumb.elem, 'height', true);

                    // grab & reset size for smoother thumbnail loads
                    if (o.thumb_fit && o.thum_crop !== true) {
                        this.setStyle(thumb.elem, { width: 0, height: 0 });
                    }

                    thumb.load(src, this.proxy(function (e) {
                        var orig = e.target.width;
                        e.scope.scale({
                            width: w,
                            height: h,
                            crop: o.thumb_crop,
                            margin: o.thumb_margin,
                            complete: this.proxy(function () {
                                // shrink thumbnails to fit
                                var top = ['left', 'top'];
                                var arr = ['Height', 'Width'];
                                this.loop(arr, function (m, i) {
                                    if ((!o.thumb_crop || o.thumb_crop == m.toLowerCase()) && o.thumb_fit) {
                                        var css = {};
                                        var opp = arr[Math.abs(i - 1)].toLowerCase();
                                        css[opp] = e.target[opp];
                                        this.setStyle(e.target.parentNode, css);
                                        var css = {};
                                        css[top[i]] = 0;
                                        this.setStyle(e.target, css);
                                    }
                                    e.scope['outer' + m] = this[m.toLowerCase()](e.target.parentNode, true);
                                });
                                // set high quality if downscale is moderate
                                this.toggleQuality(e.target, o.thumb_quality === true || (o.thumb_quality == 'auto' && orig < e.target.width * 3));
                                this.trigger({
                                    type: G.THUMBNAIL,
                                    thumbTarget: e.target,
                                    thumbOrder: e.scope.order
                                });
                            })
                        });
                    }));
                    if (o.preload == 'all') {
                        thumb.add(this.data[i].image);
                    }
                } else if (o.thumbnails == 'empty') {
                    thumb = {
                        elem: this.create('div', 'galleria-image'),
                        image: this.create('span', 'img')
                    };
                    thumb.elem.appendChild(thumb.image);
                    this.get('thumbnails').appendChild(thumb.elem);
                } else {
                    thumb = {
                        elem: false,
                        image: false
                    }
                }
                var activate = this.proxy(function (e) {
                    this.pause();
                    e.preventDefault();
                    var ind = e.currentTarget.rel;
                    if (this.active !== ind) {
                        this.show(ind);
                    }
                });
                if (o.thumbnails !== false) {
                    thumb.elem.rel = i;
                    this.listen(thumb.elem, 'click', activate);
                }
                if (o.link_source_images && o.keep_source && this.data[i].elem) {
                    this.data[i].elem.rel = i;
                    this.listen(this.data[i].elem, 'click', activate);
                }
                this.push(thumb, this.thumbnails);
            }
            this.setStyle(this.get('thumbnails'), { opacity: 0 });

            if (o.height && o.height != 'auto') {
                this.setStyle(this.get('container'), { height: o.height })
            }

            this.wait(function () {
                // the most sensitive piece of code in Galleria, we need to have all the meassurements right to continue
                var cssHeight = this.getStyle(this.get('container'), 'height', true);
                this.stageWidth = this.width(this.get('stage'));
                this.stageHeight = this.height(this.get('stage'));
                if (this.stageHeight < 50 && o.height == 'auto') {
                    // no height detected for sure, set reasonable ratio (16/9)
                    this.setStyle(this.get('container'), {
                        height: Math.round(this.stageWidth * 9 / 16)
                    });
                    this.stageHeight = this.height(this.get('stage'));
                }
                return this.stageHeight && this.stageWidth;
            }, function () {
                this.listen(this.get('image-nav-right'), 'click', this.proxy(function (e) {
                    if (o.clicknext) {
                        e.stopPropagation();
                    }
                    this.pause();
                    this.next();
                }));
                this.listen(this.get('image-nav-left'), 'click', this.proxy(function (e) {
                    if (o.clicknext) {
                        e.stopPropagation();
                    }
                    this.pause();
                    this.prev();
                }));
                this.setStyle(this.get('thumbnails'), { opacity: 1 });
                this.trigger(G.READY);
            }, function () {
                G.raise('Galleria could not load properly. Make sure stage has a height and width.');
            }, 5000);
        },

        mousePosition: function (e) {
            return {
                x: e.pageX - this.$('stage').offset().left + jQuery(document).scrollLeft(),
                y: e.pageY - this.$('stage').offset().top + jQuery(document).scrollTop()
            };
        },

        addPan: function (img) {
            var c = this.options.image_crop;
            if (c === false) {
                return;
            }
            if (this.options.image_crop === false) {
                return;
            }
            img = img || this.controls.getActive().image;
            if (img.tagName.toUpperCase() != 'IMG') {
                G.raise('Could not add pan');
            }

            var x = img.width / 2;
            var y = img.height / 2;
            var curX = destX = this.getStyle(img, 'left', true) || 0;
            var curY = destY = this.getStyle(img, 'top', true) || 0;
            var distX = 0;
            var distY = 0;
            var active = false;
            var ts = new Date().getTime();
            var calc = this.proxy(function (e) {
                if (new Date().getTime() - ts < 50) {
                    return;
                }
                active = true;
                x = this.mousePosition(e).x;
                y = this.mousePosition(e).y;
            });
            var loop = this.proxy(function (e) {
                if (!active) {
                    return;
                }
                distX = img.width - this.stageWidth;
                distY = img.height - this.stageHeight;
                destX = x / this.stageWidth * distX * -1;
                destY = y / this.stageHeight * distY * -1;
                curX += (destX - curX) / this.options.image_pan_smoothness;
                curY += (destY - curY) / this.options.image_pan_smoothness;
                if (distY > 0) {
                    this.setStyle(img, { top: Math.max(distY * -1, Math.min(0, curY)) });
                }
                if (distX > 0) {
                    this.setStyle(img, { left: Math.max(distX * -1, Math.min(0, curX)) });
                }
            });
            this.forget(this.get('stage'), 'mousemove');
            this.listen(this.get('stage'), 'mousemove', calc);
            this.addTimer('pan', loop, 30, true);
        },

        removePan: function () {
            this.forget(this.get('stage'), 'mousemove');
            this.clearTimer('pan');
        },

        parseCarousel: function (e) {
            var w = 0;
            var h = 0;
            var hooks = [0];
            this.loop(this.thumbnails, function (thumb, i) {
                if (thumb.ready) {
                    w += thumb.outerWidth || this.width(thumb.elem, true);
                    hooks[i + 1] = w;
                    h = Math.max(h, this.height(thumb.elem));
                }
            });
            this.toggleClass(this.get('thumbnails-container'), 'galleria-carousel', w > this.stageWidth);
            this.setStyle(this.get('thumbnails-list'), {
                overflow: 'hidden',
                position: 'relative' // for IE Standards mode
            });
            this.setStyle(this.get('thumbnails'), {
                width: w,
                height: h,
                position: 'relative',
                overflow: 'hidden'
            });
            if (!this.carousel) {
                this.initCarousel();
            }
            this.carousel.max = w;
            this.carousel.hooks = hooks;
            this.carousel.width = this.width(this.get('thumbnails-list'));
            this.carousel.setClasses();
        },

        initCarousel: function () {
            var c = this.carousel = {
                right: this.get('thumb-nav-right'),
                left: this.get('thumb-nav-left'),
                update: this.proxy(function () {
                    this.parseCarousel();
                    // todo: fix so the carousel moves to the left
                }),
                width: 0,
                current: 0,
                set: function (i) {
                    i = Math.max(i, 0);
                    while (c.hooks[i - 1] + c.width > c.max && i >= 0) {
                        i--;
                    }
                    c.current = i;
                    c.animate();
                },
                hooks: [],
                getLast: function (i) {
                    i = i || c.current

                    return i - 1;
                },
                follow: function (i) {
                    if (i == 0 || i == c.hooks.length - 2) {
                        c.set(i);
                        return;
                    }
                    var last = c.current;
                    while (c.hooks[last] - c.hooks[c.current] < c.width && last <= c.hooks.length) {
                        last++;
                    }
                    if (i - 1 < c.current) {
                        c.set(i - 1)
                    } else if (i + 2 > last) {
                        c.set(i - last + c.current + 2)
                    }
                },
                max: 0,
                setClasses: this.proxy(function () {
                    this.toggleClass(c.left, 'disabled', !c.current);
                    this.toggleClass(c.right, 'disabled', c.hooks[c.current] + c.width > c.max);
                }),
                animate: this.proxy(function (to) {
                    c.setClasses();
                    this.animate(this.get('thumbnails'), {
                        to: { left: c.hooks[c.current] * -1 },
                        duration: this.options.carousel_speed,
                        easing: 'galleria',
                        queue: false
                    });
                })
            };
            this.listen(c.right, 'click', this.proxy(function (e) {
                if (this.options.carousel_steps == 'auto') {
                    for (var i = c.current; i < c.hooks.length; i++) {
                        if (c.hooks[i] - c.hooks[c.current] > c.width) {
                            c.set(i - 2);
                            break;
                        }
                    }
                } else {
                    c.set(c.current + this.options.carousel_steps);
                }
            }));
            this.listen(c.left, 'click', this.proxy(function (e) {
                if (this.options.carousel_steps == 'auto') {
                    for (var i = c.current; i >= 0; i--) {
                        if (c.hooks[c.current] - c.hooks[i] > c.width) {
                            c.set(i + 2);
                            break;
                        } else if (i == 0) {
                            c.set(0);
                            break;
                        }
                    }
                } else {
                    c.set(c.current - this.options.carousel_steps);
                }
            }));
        },
        addElement: function () {
            this.loop(arguments, function (b) {
                this.dom[b] = this.create('div', 'galleria-' + b);
            });
            return this;
        },
        getDimensions: function (i) {
            return {
                w: i.width,
                h: i.height,
                cw: this.stageWidth,
                ch: this.stageHeight,
                top: (this.stageHeight - i.height) / 2,
                left: (this.stageWidth - i.width) / 2
            };
        },
        attachKeyboard: function (map) {
            this.keyboard.attach(map);
            return this;
        },
        detachKeyboard: function () {
            this.keyboard.detach();
            return this;
        },
        build: function () {
            this.append({
                'info-text':
                ['info-title', 'info-description', 'info-author'],
                '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']
            });

            this.current = this.create('span', 'current');
            this.current.innerHTML = '-';
            this.get('counter').innerHTML = ' / <span class="total">' + this.data.length + '</span>';
            this.prependChild('counter', this.current);
        },

        appendChild: function (parent, child) {
            try {
                this.get(parent).appendChild(this.get(child));
            } catch (e) { }
        },

        prependChild: function (parent, child) {
            var child = this.get(child) || child;
            try {
                this.get(parent).insertBefore(child, this.get(parent).firstChild);
            } catch (e) { }
        },

        remove: function () {
            var a = Array.prototype.slice.call(arguments);
            this.jQuery(a.join(',')).remove();
        },

        append: function (data) {
            for (var i in data) {
                if (data[i].constructor == Array) {
                    for (var j = 0; data[i][j]; j++) {
                        this.appendChild(i, data[i][j]);
                    }
                } else {
                    this.appendChild(i, data[i]);
                }
            }
            return this;
        },

        rescale: function (width, height, callback) {

            var o = this.options;
            callback = this.proxy(callback);

            if (typeof width == 'function') {
                callback = this.proxy(width);
                width = undefined;
            }

            var scale = this.proxy(function () {
                this.stageWidth = width || this.width(this.get('stage'));
                this.stageHeight = height || this.height(this.get('stage'));
                this.controls.getActive().scale({
                    width: this.stageWidth,
                    height: this.stageHeight,
                    crop: o.image_crop,
                    max: o.max_scale_ratio,
                    min: o.min_scale_ratio,
                    margin: o.image_margin,
                    position: o.image_position
                });
                if (this.carousel) {
                    this.carousel.update();
                }
                this.trigger(G.RESCALE)
                callback();
            });
            if (G.WEBKIT && !width && !height) {
                this.addTimer('scale', scale, 5); // webkit is too fast
            } else {
                scale.call(this);
            }
        },

        show: function (index, rewind, history) {
            if (!this.options.queue && this.queue.stalled) {
                return;
            }
            rewind = typeof rewind != 'undefined' ? !!rewind : index < this.active;
            history = history || false;
            index = Math.max(0, Math.min(parseInt(index), this.data.length - 1));
            if (!history && G.History) {
                G.History.value(index.toString());
                return;
            }
            this.active = index;
            this.push([index, rewind], this.queue);
            if (!this.queue.stalled) {
                this.showImage();
            }
            return this;
        },

        showImage: function () {
            var o = this.options;
            var args = this.queue[0];
            var index = args[0];
            var rewind = !!args[1];
            if (o.carousel && this.carousel && o.carousel_follow) {
                this.carousel.follow(index);
            }

            var src = this.getData(index).image;
            var active = this.controls.getActive();
            var next = this.controls.getNext();
            var cached = next.isCached(src);
            var complete = this.proxy(function () {
                this.queue.stalled = false;
                this.toggleQuality(next.image, o.image_quality);
                this.setStyle(active.elem, { zIndex: 0 });
                this.setStyle(next.elem, { zIndex: 1 });
                this.trigger({
                    type: G.IMAGE,
                    index: index,
                    imageTarget: next.image,
                    thumbTarget: this.thumbnails[index].image
                });
                if (o.image_pan) {
                    this.addPan(next.image);
                }
                this.controls.swap();
                this.moveOut(active.image);
                if (this.getData(index).link) {
                    this.setStyle(next.image, { cursor: 'pointer' });
                    this.listen(next.image, 'click', this.proxy(function () {
                        if (o.popup_links) {
                            var win = window.open(this.getData(index).link, '_blank');
                        } else {
                            window.location.href = this.getData(index).link;
                        }
                    }));
                }
                Array.prototype.shift.call(this.queue);
                if (this.queue.length) {
                    this.showImage();
                }
                this.playCheck();
            });
            if (typeof o.preload == 'number' && o.preload > 0) {
                var p, n = this.getNext();
                try {
                    for (var i = o.preload; i > 0; i--) {
                        p = new Picture();
                        p.add(this.getData(n).image);
                        n = this.getNext(n);
                    }
                } catch (e) { }
            }
            this.trigger({
                type: G.LOADSTART,
                cached: cached,
                index: index,
                imageTarget: next.image,
                thumbTarget: this.thumbnails[index].image
            });

            jQuery(this.thumbnails[index].elem).addClass('active').siblings('.active').removeClass('active');

            next.load(src, this.proxy(function (e) {
                next.scale({
                    width: this.stageWidth,
                    height: this.stageHeight,
                    crop: o.image_crop,
                    max: o.max_scale_ratio,
                    min: o.min_scale_ratio,
                    margin: o.image_margin,
                    position: o.image_position,
                    complete: this.proxy(function () {
                        if (active.image) {
                            this.toggleQuality(active.image, false);
                        }
                        this.toggleQuality(next.image, false);
                        this.trigger({
                            type: G.LOADFINISH,
                            cached: cached,
                            index: index,
                            imageTarget: next.image,
                            thumbTarget: this.thumbnails[index].image
                        });
                        this.queue.stalled = true;
                        var transition = G.transitions[o.transition] || o.transition;
                        this.removePan();
                        this.setInfo(index);
                        this.setCounter(index);
                        if (typeof transition == 'function') {
                            transition.call(this, {
                                prev: active.image,
                                next: next.image,
                                rewind: rewind,
                                speed: o.transition_speed || 400
                            }, complete);
                        } else {
                            complete();
                        }
                    })
                });
            }));
        },

        getNext: function (base) {
            base = typeof base == 'number' ? base : this.active;
            return base == this.data.length - 1 ? 0 : base + 1;
        },

        getPrev: function (base) {
            base = typeof base == 'number' ? base : this.active;
            return base === 0 ? this.data.length - 1 : base - 1;
        },

        next: function () {
            if (this.data.length > 1) {
                this.show(this.getNext(), false);
            }
            return this;
        },

        prev: function () {
            if (this.data.length > 1) {
                this.show(this.getPrev(), true);
            }
            return this;
        },

        get: function (elem) {
            return elem in this.dom ? this.dom[elem] : null;
        },

        getData: function (index) {
            return this.data[index] || this.data[this.active];
        },

        getIndex: function () {
            return typeof this.active === 'number' ? this.active : 0;
        },

        play: function (delay) {
            this.trigger(G.PLAY);
            this.playing = true;
            this.playtime = delay || this.playtime;
            this.playCheck();
            return this;
        },

        pause: function () {
            this.trigger(G.PAUSE);
            this.playing = false;
            return this;
        },

        playCheck: function () {
            var p = 0;
            var i = 20; // the interval
            var ts = function () {
                return new Date().getTime();
            }
            var now = ts();
            if (this.playing) {
                this.clearTimer('play');
                var fn = this.proxy(function () {
                    p = ts() - now;
                    if (p >= this.playtime && this.playing) {
                        this.clearTimer('play');
                        this.next();
                        return;
                    }
                    if (this.playing) {
                        this.trigger({
                            type: G.PROGRESS,
                            percent: Math.ceil(p / this.playtime * 100),
                            seconds: Math.floor(p / 1000),
                            milliseconds: p
                        });
                        this.addTimer('play', fn, i);
                    }
                });
                this.addTimer('play', fn, i);
            }
        },

        setActive: function (val) {
            this.active = val;
            return this;
        },

        setCounter: function (index) {
            index = index || this.active;
            this.current.innerHTML = index + 1;
            return this;
        },

        setInfo: function (index) {
            var data = this.getData(index || this.active);
            this.loop(['title', 'description', 'author'], function (type) {
                var elem = this.get('info-' + type);
                var fn = data[type] && data[type].length ? 'reveal' : 'hide';
                this[fn](elem);
                if (data[type]) {
                    elem.innerHTML = data[type];
                }
            });
            return this;
        },

        hasInfo: function (index) {
            var d = this.getData(index);
            var check = 'title description author'.split(' ');
            for (var i = 0; check[i]; i++) {
                if (d[check[i]] && d[check[i]].length) {
                    return true;
                }
            }
            return false;
        },

        getDataObject: function (o) {
            var obj = {
                image: '',
                thumb: '',
                title: '',
                description: '',
                author: '',
                link: ''
            };
            return o ? this.mix(obj, o) : obj;
        },

        jQuery: function (str) {
            var ret = [];
            this.loop(str.split(','), this.proxy(function (elem) {
                elem = elem.replace(/^\s\s*/, "").replace(/\s\s*$/, "");
                if (this.get(elem)) {
                    ret.push(elem);
                }
            }));
            var jQ = jQuery(this.get(ret.shift()));
            this.loop(ret, this.proxy(function (elem) {
                jQ = jQ.add(this.get(elem));
            }));
            return jQ;
        },

        $: function (str) {
            return this.jQuery(str);
        },

        toggleQuality: function (img, force) {
            if (!G.IE7 || typeof img == 'undefined' || !img) {
                return this;
            }
            if (typeof force === 'undefined') {
                force = img.style.msInterpolationMode == 'nearest-neighbor';
            }
            img.style.msInterpolationMode = force ? 'bicubic' : 'nearest-neighbor';

            return this;
        },

        unload: function () {
            //TODO
        },

        load: function () {
            var loaded = 0;
            var o = this.options;
            if (
            (o.data_type == 'auto' &&
                typeof o.data_source == 'object' &&
                !(o.data_source instanceof jQuery) &&
                !o.data_source.tagName
            ) || o.data_type == 'json' || o.data_source.constructor == Array) {
                this.data = o.data_source;
                this.trigger(G.DATA);

            } else { // assume selector
                var images = jQuery(o.data_source).find(o.data_image_selector);
                var getData = this.proxy(function (elem) {
                    var i, j, anchor = elem.parentNode;
                    if (anchor && anchor.nodeName == 'A') {
                        if (anchor.href.match(/\.(png|gif|jpg|jpeg)/i)) {
                            i = anchor.href;
                        } else {
                            j = anchor.href;
                        }
                    }
                    var obj = this.getDataObject({
                        title: elem.title,
                        thumb: elem.src,
                        image: i || elem.src,
                        description: elem.alt,
                        link: j || elem.getAttribute('longdesc'),
                        elem: elem
                    });
                    return this.mix(obj, o.data_config(elem));
                });
                this.loop(images, function (elem) {
                    loaded++;
                    this.push(getData(elem), this.data);
                    if (!o.keep_source && !Galleria.IE) {
                        elem.parentNode.removeChild(elem);
                    }
                    if (loaded == images.length) {
                        this.trigger(G.DATA);
                    }
                });
            }
        }
    });

    G.log = function () {
        try {
            console.log.apply(console, Array.prototype.slice.call(arguments));
        } catch (e) {
            try {
                opera.postError.apply(opera, arguments);
            } catch (er) {
                alert(Array.prototype.join.call(arguments, " "));
            }
        }
    };

    var nav = navigator.userAgent.toLowerCase();
    var hash = window.location.hash.replace(/#\//, '');

    G.DATA = 'data';
    G.READY = 'ready';
    G.THUMBNAIL = 'thumbnail';
    G.LOADSTART = 'loadstart';
    G.LOADFINISH = 'loadfinish';
    G.IMAGE = 'image';
    G.THEMELOAD = 'themeload';
    G.PLAY = 'play';
    G.PAUSE = 'pause';
    G.PROGRESS = 'progress';
    G.FULLSCREEN_ENTER = 'fullscreen_enter';
    G.FULLSCREEN_EXIT = 'fullscreen_exit';
    G.IDLE_ENTER = 'idle_enter';
    G.IDLE_EXIT = 'idle_exit';
    G.RESCALE = 'rescale';
    G.LIGHTBOX_OPEN = 'lightbox_open';
    G.LIGHTBOX_CLOSE = 'lightbox_cloe';
    G.LIGHTBOX_IMAGE = 'lightbox_image';

    G.IE8 = (typeof (XDomainRequest) !== 'undefined')
    G.IE7 = !!(window.XMLHttpRequest && document.expando);
    G.IE6 = (!window.XMLHttpRequest);
    G.IE = !!(G.IE6 || G.IE7);
    G.WEBKIT = /webkit/.test(nav);
    G.SAFARI = /safari/.test(nav);
    G.CHROME = /chrome/.test(nav);
    G.QUIRK = (G.IE && document.compatMode && document.compatMode == "BackCompat");
    G.MAC = /mac/.test(navigator.platform.toLowerCase());
    G.OPERA = !!window.opera

    G.Picture = Picture;

    G.addTheme = function (obj) {
        var theme = {};
        var orig = ['name', 'author', 'version', 'defaults', 'init'];
        var proto = G.prototype;
        proto.loop(orig, function (val) {
            if (!obj[val]) {
                G.raise(val + ' not specified in theme.');
            }
            if (val != 'name' && val != 'init') {
                theme[val] = obj[val];
            }
        });
        theme.init = obj.init;

        if (obj.css) {
            var css;
            proto.loop(proto.getElements('script'), function (el) {
                var reg = new RegExp('galleria.' + obj.name.toLowerCase() + '.js');
                if (reg.test(el.src)) {
                    css = el.src.replace(/[^\/]*$/, "") + obj.css;
                    proto.loadCSS(css, function () {
                        G.theme = theme;
                        jQuery(document).trigger(G.THEMELOAD);
                    });
                }
            });
            if (!css) {
                G.raise('No theme CSS loaded');
            }
        }
        return theme;
    };

    G.raise = function (msg) {
        if (G.debug) {
            throw new Error(msg);
        }
    };

    G.loadTheme = function (src) {
        G.prototype.loadScript(src);
    };

    G.galleries = [];
    G.get = function (index) {
        if (G.galleries[index]) {
            return G.galleries[index];
        } else if (typeof index !== 'number') {
            return G.galleries;
        } else {
            G.raise('Gallery index not found');
        }
    }

    jQuery.easing.galleria = function (x, t, b, c, d) {
        if ((t /= d / 2) < 1) {
            return c / 2 * t * t * t * t + b;
        }
        return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
    };

    G.transitions = {
        add: function (name, fn) {
            if (name != arguments.callee.name) {
                this[name] = fn;
            }
        },
        fade: function (params, complete) {
            jQuery(params.next).show().css('opacity', 0).animate({
                opacity: 1
            }, params.speed, complete);
            if (params.prev) {
                jQuery(params.prev).css('opacity', 1).animate({
                    opacity: 0
                }, params.speed);
            }
        },
        flash: function (params, complete) {
            jQuery(params.next).css('opacity', 0);
            if (params.prev) {
                jQuery(params.prev).animate({
                    opacity: 0
                }, (params.speed / 2), function () {
                    jQuery(params.next).animate({
                        opacity: 1
                    }, params.speed, complete);
                });
            } else {
                jQuery(params.next).animate({
                    opacity: 1
                }, params.speed, complete);
            }
        },
        pulse: function (params, complete) {
            if (params.prev) {
                jQuery(params.prev).css('opacity', 0);
            }
            jQuery(params.next).css('opacity', 0).animate({
                opacity: 1
            }, params.speed, complete);
        },
        slide: function (params, complete) {
            var image = jQuery(params.next).parent();
            var images = this.$('images');
            var width = this.stageWidth;
            image.css({
                left: width * (params.rewind ? -1 : 1)
            });
            images.animate({
                left: width * (params.rewind ? 1 : -1)
            }, {
                duration: params.speed,
                queue: false,
                easing: 'galleria',
                complete: function () {
                    images.css('left', 0);
                    image.css('left', 0);
                    complete();
                }
            });
        },
        fadeslide: function (params, complete) {
            if (params.prev) {
                jQuery(params.prev).css({
                    opacity: 1,
                    left: 0
                }).animate({
                    opacity: 0,
                    left: 50 * (params.rewind ? 1 : -1)
                }, {
                    duration: params.speed,
                    queue: false,
                    easing: 'swing'
                });
            }
            jQuery(params.next).css({
                left: 50 * (params.rewind ? -1 : 1),
                opacity: 0
            }).animate({
                opacity: 1,
                left: 0
            }, {
                duration: params.speed,
                complete: complete,
                queue: false,
                easing: 'swing'
            });
        }
    };

    G.addTransition = function () {
        G.transitions.add.apply(this, arguments);
    }

    jQuery.fn.galleria = function (options) {

        options = options || {};
        var selector = this.selector;

        return this.each(function () {
            if (!options.keep_source) {
                jQuery(this).children().hide();
            }

            options = G.prototype.mix(options, { target: this });
            var height = G.prototype.height(this) || G.prototype.getStyle(this, 'height', true);
            if (!options.height && height) {
                options = G.prototype.mix({ height: height }, options);
            }

            G.debug = !!options.debug;

            var gallery = new G(options);

            Galleria.galleries.push(gallery);

            if (G.theme) {
                gallery.init();
            } else {
                jQuery(document).bind(G.THEMELOAD, function () {
                    gallery.init();
                });
            }
        })
    };


})();

//-----------------------------------------------------------------------------------------------
//      FANCY BOX
//-----------------------------------------------------------------------------------------------
/*
 * FancyBox - jQuery Plugin
 * Simple and fancy lightbox alternative
 *
 * Examples and documentation at: http://fancybox.net
 * 
 * Copyright (c) 2008 - 2010 Janis Skarnelis
 *
 * Version: 1.3.1 (05/03/2010)
 * Requires: jQuery v1.3+
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 */

(function($) {

	var tmp, loading, overlay, wrap, outer, inner, close, nav_left, nav_right,

		selectedIndex = 0, selectedOpts = {}, selectedArray = [], currentIndex = 0, currentOpts = {}, currentArray = [],

		ajaxLoader = null, imgPreloader = new Image(), imgRegExp = /\.(jpg|gif|png|bmp|jpeg)(.*)?$/i, swfRegExp = /[^\.]\.(swf)\s*$/i,

		loadingTimer, loadingFrame = 1,

		start_pos, final_pos, busy = false, shadow = 20, fx = $.extend($('<div/>')[0], { prop: 0 }), titleh = 0, 

		isIE6 = !$.support.opacity && !window.XMLHttpRequest,

		/*
		 * Private methods 
		 */

		fancybox_abort = function() {
			loading.hide();

			imgPreloader.onerror = imgPreloader.onload = null;

			if (ajaxLoader) {
				ajaxLoader.abort();
			}

			tmp.empty();
		},

		fancybox_error = function() {
			$.fancybox('<p id="fancybox_error">The requested content cannot be loaded.<br />Please try again later.</p>', {
				'scrolling'		: 'no',
				'padding'		: 20,
				'transitionIn'	: 'none',
				'transitionOut'	: 'none'
			});
		},

		fancybox_get_viewport = function() {
			return [ $(window).width(), $(window).height(), $(document).scrollLeft(), $(document).scrollTop() ];
		},

		fancybox_get_zoom_to = function () {
			var view	= fancybox_get_viewport(),
				to		= {},

				margin = currentOpts.margin,
				resize = currentOpts.autoScale,

				horizontal_space	= (shadow + margin) * 2,
				vertical_space		= (shadow + margin) * 2,
				double_padding		= (currentOpts.padding * 2),
				
				ratio;

			if (currentOpts.width.toString().indexOf('%') > -1) {
				to.width = ((view[0] * parseFloat(currentOpts.width)) / 100) - (shadow * 2) ;
				resize = false;

			} else {
				to.width = currentOpts.width + double_padding;
			}

			if (currentOpts.height.toString().indexOf('%') > -1) {
				to.height = ((view[1] * parseFloat(currentOpts.height)) / 100) - (shadow * 2);
				resize = false;

			} else {
				to.height = currentOpts.height + double_padding;
			}

			if (resize && (to.width > (view[0] - horizontal_space) || to.height > (view[1] - vertical_space))) {
				if (selectedOpts.type == 'image' || selectedOpts.type == 'swf') {
					horizontal_space	+= double_padding;
					vertical_space		+= double_padding;

					ratio = Math.min(Math.min( view[0] - horizontal_space, currentOpts.width) / currentOpts.width, Math.min( view[1] - vertical_space, currentOpts.height) / currentOpts.height);

					to.width	= Math.round(ratio * (to.width	- double_padding)) + double_padding;
					to.height	= Math.round(ratio * (to.height	- double_padding)) + double_padding;

				} else {
					to.width	= Math.min(to.width,	(view[0] - horizontal_space));
					to.height	= Math.min(to.height,	(view[1] - vertical_space));
				}
			}

			to.top	= view[3] + ((view[1] - (to.height	+ (shadow * 2 ))) * 0.5);
			to.left	= view[2] + ((view[0] - (to.width	+ (shadow * 2 ))) * 0.5);

			if (currentOpts.autoScale === false) {
				to.top	= Math.max(view[3] + margin, to.top);
				to.left	= Math.max(view[2] + margin, to.left);
			}

			return to;
		},

		fancybox_format_title = function(title) {
			if (title && title.length) {
				switch (currentOpts.titlePosition) {
					case 'inside':
						return title;
					case 'over':
						return '<span id="fancybox-title-over">' + title + '</span>';
					default:
						return '<span id="fancybox-title-wrap"><span id="fancybox-title-left"></span><span id="fancybox-title-main">' + title + '</span><span id="fancybox-title-right"></span></span>';
				}
			}

			return false;
		},

		fancybox_process_title = function() {
			var title	= currentOpts.title,
				width	= final_pos.width - (currentOpts.padding * 2),
				titlec	= 'fancybox-title-' + currentOpts.titlePosition;
				
			$('#fancybox-title').remove();

			titleh = 0;

			if (currentOpts.titleShow === false) {
				return;
			}

			title = $.isFunction(currentOpts.titleFormat) ? currentOpts.titleFormat(title, currentArray, currentIndex, currentOpts) : fancybox_format_title(title);

			if (!title || title === '') {
				return;
			}

			$('<div id="fancybox-title" class="' + titlec + '" />').css({
				'width'			: width,
				'paddingLeft'	: currentOpts.padding,
				'paddingRight'	: currentOpts.padding
			}).html(title).appendTo('body');

			switch (currentOpts.titlePosition) {
				case 'inside':
					titleh = $("#fancybox-title").outerHeight(true) - currentOpts.padding;
					final_pos.height += titleh;
				break;

				case 'over':
					$('#fancybox-title').css('bottom', currentOpts.padding);
				break;

				default:
					$('#fancybox-title').css('bottom', $("#fancybox-title").outerHeight(true) * -1);
				break;
			}

			$('#fancybox-title').appendTo( outer ).hide();
		},

		fancybox_set_navigation = function() {
			$(document).unbind('keydown.fb').bind('keydown.fb', function(e) {
				if (e.keyCode == 27 && currentOpts.enableEscapeButton) {
					e.preventDefault();
					$.fancybox.close();

				} else if (e.keyCode == 37) {
					e.preventDefault();
					$.fancybox.prev();

				} else if (e.keyCode == 39) {
					e.preventDefault();
					$.fancybox.next();
				}
			});

			if ($.fn.mousewheel) {
				wrap.unbind('mousewheel.fb');

				if (currentArray.length > 1) {
					wrap.bind('mousewheel.fb', function(e, delta) {
						e.preventDefault();

						if (busy || delta === 0) {
							return;
						}

						if (delta > 0) {
							$.fancybox.prev();
						} else {
							$.fancybox.next();
						}
					});
				}
			}

			if (!currentOpts.showNavArrows) { return; }

			if ((currentOpts.cyclic && currentArray.length > 1) || currentIndex !== 0) {
				nav_left.show();
			}

			if ((currentOpts.cyclic && currentArray.length > 1) || currentIndex != (currentArray.length -1)) {
				nav_right.show();
			}
		},

		fancybox_preload_images = function() {
			var href, 
				objNext;
				
			if ((currentArray.length -1) > currentIndex) {
				href = currentArray[ currentIndex + 1 ].href;

				if (typeof href !== 'undefined' && href.match(imgRegExp)) {
					objNext = new Image();
					objNext.src = href;
				}
			}

			if (currentIndex > 0) {
				href = currentArray[ currentIndex - 1 ].href;

				if (typeof href !== 'undefined' && href.match(imgRegExp)) {
					objNext = new Image();
					objNext.src = href;
				}
			}
		},

		_finish = function () {
			inner.css('overflow', (currentOpts.scrolling == 'auto' ? (currentOpts.type == 'image' || currentOpts.type == 'iframe' || currentOpts.type == 'swf' ? 'hidden' : 'auto') : (currentOpts.scrolling == 'yes' ? 'auto' : 'visible')));

			if (!$.support.opacity) {
				inner.get(0).style.removeAttribute('filter');
				wrap.get(0).style.removeAttribute('filter');
			}

			$('#fancybox-title').show();

			if (currentOpts.hideOnContentClick)	{
				inner.one('click', $.fancybox.close);
			}
			if (currentOpts.hideOnOverlayClick)	{
				overlay.one('click', $.fancybox.close);
			}

			if (currentOpts.showCloseButton) {
				close.show();
			}

			fancybox_set_navigation();

			$(window).bind("resize.fb", $.fancybox.center);

			if (currentOpts.centerOnScroll) {
				$(window).bind("scroll.fb", $.fancybox.center);
			} else {
				$(window).unbind("scroll.fb");
			}

			if ($.isFunction(currentOpts.onComplete)) {
				currentOpts.onComplete(currentArray, currentIndex, currentOpts);
			}

			busy = false;

			fancybox_preload_images();
		},

		fancybox_draw = function(pos) {
			var width	= Math.round(start_pos.width	+ (final_pos.width	- start_pos.width)	* pos),
				height	= Math.round(start_pos.height	+ (final_pos.height	- start_pos.height)	* pos),

				top		= Math.round(start_pos.top	+ (final_pos.top	- start_pos.top)	* pos),
				left	= Math.round(start_pos.left	+ (final_pos.left	- start_pos.left)	* pos);

			wrap.css({
				'width'		: width		+ 'px',
				'height'	: height	+ 'px',
				'top'		: top		+ 'px',
				'left'		: left		+ 'px'
			});

			width	= Math.max(width - currentOpts.padding * 2, 0);
			height	= Math.max(height - (currentOpts.padding * 2 + (titleh * pos)), 0);

			inner.css({
				'width'		: width		+ 'px',
				'height'	: height	+ 'px'
			});

			if (typeof final_pos.opacity !== 'undefined') {
				wrap.css('opacity', (pos < 0.5 ? 0.5 : pos));
			}
		},

		fancybox_get_obj_pos = function(obj) {
			var pos		= obj.offset();

			pos.top		+= parseFloat( obj.css('paddingTop') )	|| 0;
			pos.left	+= parseFloat( obj.css('paddingLeft') )	|| 0;

			pos.top		+= parseFloat( obj.css('border-top-width') )	|| 0;
			pos.left	+= parseFloat( obj.css('border-left-width') )	|| 0;

			pos.width	= obj.width();
			pos.height	= obj.height();

			return pos;
		},

		fancybox_get_zoom_from = function() {
			var orig = selectedOpts.orig ? $(selectedOpts.orig) : false,
				from = {},
				pos,
				view;

			if (orig && orig.length) {
				pos = fancybox_get_obj_pos(orig);

				from = {
					width	: (pos.width	+ (currentOpts.padding * 2)),
					height	: (pos.height	+ (currentOpts.padding * 2)),
					top		: (pos.top		- currentOpts.padding - shadow),
					left	: (pos.left		- currentOpts.padding - shadow)
				};
				
			} else {
				view = fancybox_get_viewport();

				from = {
					width	: 1,
					height	: 1,
					top		: view[3] + view[1] * 0.5,
					left	: view[2] + view[0] * 0.5
				};
			}

			return from;
		},

		fancybox_show = function() {
			loading.hide();

			if (wrap.is(":visible") && $.isFunction(currentOpts.onCleanup)) {
				if (currentOpts.onCleanup(currentArray, currentIndex, currentOpts) === false) {
					$.event.trigger('fancybox-cancel');

					busy = false;
					return;
				}
			}

			currentArray	= selectedArray;
			currentIndex	= selectedIndex;
			currentOpts		= selectedOpts;

			inner.get(0).scrollTop	= 0;
			inner.get(0).scrollLeft	= 0;

			if (currentOpts.overlayShow) {
				if (isIE6) {
					$('select:not(#fancybox-tmp select)').filter(function() {
						return this.style.visibility !== 'hidden';
					}).css({'visibility':'hidden'}).one('fancybox-cleanup', function() {
						this.style.visibility = 'inherit';
					});
				}

				overlay.css({
					'background-color'	: currentOpts.overlayColor,
					'opacity'			: currentOpts.overlayOpacity
				}).unbind().show();
			}

			final_pos = fancybox_get_zoom_to();

			fancybox_process_title();

			if (wrap.is(":visible")) {
				$( close.add( nav_left ).add( nav_right ) ).hide();

				var pos = wrap.position(),
					equal;

				start_pos = {
					top		:	pos.top ,
					left	:	pos.left,
					width	:	wrap.width(),
					height	:	wrap.height()
				};

				equal = (start_pos.width == final_pos.width && start_pos.height == final_pos.height);

				inner.fadeOut(currentOpts.changeFade, function() {
					var finish_resizing = function() {
						inner.html( tmp.contents() ).fadeIn(currentOpts.changeFade, _finish);
					};
					
					$.event.trigger('fancybox-change');

					inner.empty().css('overflow', 'hidden');

					if (equal) {
						inner.css({
							top			: currentOpts.padding,
							left		: currentOpts.padding,
							width		: Math.max(final_pos.width	- (currentOpts.padding * 2), 1),
							height		: Math.max(final_pos.height	- (currentOpts.padding * 2) - titleh, 1)
						});
						
						finish_resizing();

					} else {
						inner.css({
							top			: currentOpts.padding,
							left		: currentOpts.padding,
							width		: Math.max(start_pos.width	- (currentOpts.padding * 2), 1),
							height		: Math.max(start_pos.height	- (currentOpts.padding * 2), 1)
						});
						
						fx.prop = 0;

						$(fx).animate({ prop: 1 }, {
							 duration	: currentOpts.changeSpeed,
							 easing		: currentOpts.easingChange,
							 step		: fancybox_draw,
							 complete	: finish_resizing
						});
					}
				});

				return;
			}

			wrap.css('opacity', 1);

			if (currentOpts.transitionIn == 'elastic') {
				start_pos = fancybox_get_zoom_from();

				inner.css({
						top			: currentOpts.padding,
						left		: currentOpts.padding,
						width		: Math.max(start_pos.width	- (currentOpts.padding * 2), 1),
						height		: Math.max(start_pos.height	- (currentOpts.padding * 2), 1)
					})
					.html( tmp.contents() );

				wrap.css(start_pos).show();

				if (currentOpts.opacity) {
					final_pos.opacity = 0;
				}

				fx.prop = 0;

				$(fx).animate({ prop: 1 }, {
					 duration	: currentOpts.speedIn,
					 easing		: currentOpts.easingIn,
					 step		: fancybox_draw,
					 complete	: _finish
				});

			} else {
				inner.css({
						top			: currentOpts.padding,
						left		: currentOpts.padding,
						width		: Math.max(final_pos.width	- (currentOpts.padding * 2), 1),
						height		: Math.max(final_pos.height	- (currentOpts.padding * 2) - titleh, 1)
					})
					.html( tmp.contents() );

				wrap.css( final_pos ).fadeIn( currentOpts.transitionIn == 'none' ? 0 : currentOpts.speedIn, _finish );
			}
		},

		fancybox_process_inline = function() {
			tmp.width(	selectedOpts.width );
			tmp.height(	selectedOpts.height );

			if (selectedOpts.width	== 'auto') {
				selectedOpts.width = tmp.width();
			}
			if (selectedOpts.height	== 'auto') {
				selectedOpts.height	= tmp.height();
			}

			fancybox_show();
		},
		
		fancybox_process_image = function() {
			busy = true;

			selectedOpts.width	= imgPreloader.width;
			selectedOpts.height	= imgPreloader.height;

			$("<img />").attr({
				'id'	: 'fancybox-img',
				'src'	: imgPreloader.src,
				'alt'	: selectedOpts.title
			}).appendTo( tmp );

			fancybox_show();
		},

		fancybox_start = function() {
			fancybox_abort();

			var obj	= selectedArray[ selectedIndex ],
				href, 
				type, 
				title,
				str,
				emb,
				selector,
				data;

			selectedOpts = $.extend({}, $.fn.fancybox.defaults, (typeof $(obj).data('fancybox') == 'undefined' ? selectedOpts : $(obj).data('fancybox')));
			title = obj.title || $(obj).title || selectedOpts.title || '';
			
			if (obj.nodeName && !selectedOpts.orig) {
				selectedOpts.orig = $(obj).children("img:first").length ? $(obj).children("img:first") : $(obj);
			}

			if (title === '' && selectedOpts.orig) {
				title = selectedOpts.orig.attr('alt');
			}

			if (obj.nodeName && (/^(?:javascript|#)/i).test(obj.href)) {
				href = selectedOpts.href || null;
			} else {
				href = selectedOpts.href || obj.href || null;
			}

			if (selectedOpts.type) {
				type = selectedOpts.type;

				if (!href) {
					href = selectedOpts.content;
				}
				
			} else if (selectedOpts.content) {
				type	= 'html';

			} else if (href) {
				if (href.match(imgRegExp)) {
					type = 'image';

				} else if (href.match(swfRegExp)) {
					type = 'swf';

				} else if ($(obj).hasClass("iframe")) {
					type = 'iframe';

				} else if (href.match(/#/)) {
					obj = href.substr(href.indexOf("#"));

					type = $(obj).length > 0 ? 'inline' : 'ajax';
				} else {
					type = 'ajax';
				}
			} else {
				type = 'inline';
			}

			selectedOpts.type	= type;
			selectedOpts.href	= href;
			selectedOpts.title	= title;

			if (selectedOpts.autoDimensions && selectedOpts.type !== 'iframe' && selectedOpts.type !== 'swf') {
				selectedOpts.width		= 'auto';
				selectedOpts.height		= 'auto';
			}

			if (selectedOpts.modal) {
				selectedOpts.overlayShow		= true;
				selectedOpts.hideOnOverlayClick	= false;
				selectedOpts.hideOnContentClick	= false;
				selectedOpts.enableEscapeButton	= false;
				selectedOpts.showCloseButton	= false;
			}

			if ($.isFunction(selectedOpts.onStart)) {
				if (selectedOpts.onStart(selectedArray, selectedIndex, selectedOpts) === false) {
					busy = false;
					return;
				}
			}

			tmp.css('padding', (shadow + selectedOpts.padding + selectedOpts.margin));

			$('.fancybox-inline-tmp').unbind('fancybox-cancel').bind('fancybox-change', function() {
				$(this).replaceWith(inner.children());
			});

			switch (type) {
				case 'html' :
					tmp.html( selectedOpts.content );
					fancybox_process_inline();
				break;

				case 'inline' :
					$('<div class="fancybox-inline-tmp" />').hide().insertBefore( $(obj) ).bind('fancybox-cleanup', function() {
						$(this).replaceWith(inner.children());
					}).bind('fancybox-cancel', function() {
						$(this).replaceWith(tmp.children());
					});

					$(obj).appendTo(tmp);

					fancybox_process_inline();
				break;

				case 'image':
					busy = false;

					$.fancybox.showActivity();

					imgPreloader = new Image();

					imgPreloader.onerror = function() {
						fancybox_error();
					};

					imgPreloader.onload = function() {
						imgPreloader.onerror = null;
						imgPreloader.onload = null;
						fancybox_process_image();
					};

					imgPreloader.src = href;
		
				break;

				case 'swf':
					str = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="' + selectedOpts.width + '" height="' + selectedOpts.height + '"><param name="movie" value="' + href + '"></param>';
					emb = '';
					
					$.each(selectedOpts.swf, function(name, val) {
						str += '<param name="' + name + '" value="' + val + '"></param>';
						emb += ' ' + name + '="' + val + '"';
					});

					str += '<embed src="' + href + '" type="application/x-shockwave-flash" width="' + selectedOpts.width + '" height="' + selectedOpts.height + '"' + emb + '></embed></object>';

					tmp.html(str);

					fancybox_process_inline();
				break;

				case 'ajax':
					selector	= href.split('#', 2);
					data		= selectedOpts.ajax.data || {};

					if (selector.length > 1) {
						href = selector[0];

						if (typeof data == "string") {
							data += '&selector=' + selector[1];
						} else {
							data.selector = selector[1];
						}
					}

					busy = false;
					$.fancybox.showActivity();

					ajaxLoader = $.ajax($.extend(selectedOpts.ajax, {
						url		: href,
						data	: data,
						error	: fancybox_error,
						success : function(data, textStatus, XMLHttpRequest) {
							if (ajaxLoader.status == 200) {
								tmp.html( data );
								fancybox_process_inline();
							}
						}
					}));

				break;

				case 'iframe' :
					$('<iframe id="fancybox-frame" name="fancybox-frame' + new Date().getTime() + '" frameborder="0" hspace="0" scrolling="' + selectedOpts.scrolling + '" src="' + selectedOpts.href + '"></iframe>').appendTo(tmp);
					fancybox_show();
				break;
			}
		},

		fancybox_animate_loading = function() {
			if (!loading.is(':visible')){
				clearInterval(loadingTimer);
				return;
			}

			$('div', loading).css('top', (loadingFrame * -40) + 'px');

			loadingFrame = (loadingFrame + 1) % 12;
		},

		fancybox_init = function() {
			if ($("#fancybox-wrap").length) {
				return;
			}

			$('body').append(
				tmp			= $('<div id="fancybox-tmp"></div>'),
				loading		= $('<div id="fancybox-loading"><div></div></div>'),
				overlay		= $('<div id="fancybox-overlay"></div>'),
				wrap		= $('<div id="fancybox-wrap"></div>')
			);

			if (!$.support.opacity) {
				wrap.addClass('fancybox-ie');
				loading.addClass('fancybox-ie');
			}

			outer = $('<div id="fancybox-outer"></div>')
				.append('<div class="fancy-bg" id="fancy-bg-n"></div><div class="fancy-bg" id="fancy-bg-ne"></div><div class="fancy-bg" id="fancy-bg-e"></div><div class="fancy-bg" id="fancy-bg-se"></div><div class="fancy-bg" id="fancy-bg-s"></div><div class="fancy-bg" id="fancy-bg-sw"></div><div class="fancy-bg" id="fancy-bg-w"></div><div class="fancy-bg" id="fancy-bg-nw"></div>')
				.appendTo( wrap );

			outer.append(
				inner		= $('<div id="fancybox-inner"></div>'),
				close		= $('<a id="fancybox-close"></a>'),

				nav_left	= $('<a href="javascript:;" id="fancybox-left"><span class="fancy-ico" id="fancybox-left-ico"></span></a>'),
				nav_right	= $('<a href="javascript:;" id="fancybox-right"><span class="fancy-ico" id="fancybox-right-ico"></span></a>')
			);

			close.click($.fancybox.close);
			loading.click($.fancybox.cancel);

			nav_left.click(function(e) {
				e.preventDefault();
				$.fancybox.prev();
			});

			nav_right.click(function(e) {
				e.preventDefault();
				$.fancybox.next();
			});

			if (isIE6) {
				overlay.get(0).style.setExpression('height',	"document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px'");
				loading.get(0).style.setExpression('top',		"(-20 + (document.documentElement.clientHeight ? document.documentElement.clientHeight/2 : document.body.clientHeight/2 ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop )) + 'px'");

				outer.prepend('<iframe id="fancybox-hide-sel-frame" src="javascript:\'\';" scrolling="no" frameborder="0" ></iframe>');
			}
		};

	/*
	 * Public methods 
	 */

	$.fn.fancybox = function(options) {
		$(this)
			.data('fancybox', $.extend({}, options, ($.metadata ? $(this).metadata() : {})))
			.unbind('click.fb').bind('click.fb', function(e) {
				e.preventDefault();

				if (busy) {
					return;
				}

				busy = true;

				$(this).blur();

				selectedArray	= [];
				selectedIndex	= 0;

				var rel = $(this).attr('rel') || '';

				if (!rel || rel == '' || rel === 'nofollow') {
					selectedArray.push(this);

				} else {
					selectedArray	= $("a[rel=" + rel + "], area[rel=" + rel + "]");
					selectedIndex	= selectedArray.index( this );
				}

				fancybox_start();

				return false;
			});

		return this;
	};

	$.fancybox = function(obj) {
		if (busy) {
			return;
		}

		busy = true;

		var opts = typeof arguments[1] !== 'undefined' ? arguments[1] : {};

		selectedArray	= [];
		selectedIndex	= opts.index || 0;

		if ($.isArray(obj)) {
			for (var i = 0, j = obj.length; i < j; i++) {
				if (typeof obj[i] == 'object') {
					$(obj[i]).data('fancybox', $.extend({}, opts, obj[i]));
				} else {
					obj[i] = $({}).data('fancybox', $.extend({content : obj[i]}, opts));
				}
			}

			selectedArray = jQuery.merge(selectedArray, obj);

		} else {
			if (typeof obj == 'object') {
				$(obj).data('fancybox', $.extend({}, opts, obj));
			} else {
				obj = $({}).data('fancybox', $.extend({content : obj}, opts));
			}

			selectedArray.push(obj);
		}

		if (selectedIndex > selectedArray.length || selectedIndex < 0) {
			selectedIndex = 0;
		}

		fancybox_start();
	};

	$.fancybox.showActivity = function() {
		clearInterval(loadingTimer);

		loading.show();
		loadingTimer = setInterval(fancybox_animate_loading, 66);
	};

	$.fancybox.hideActivity = function() {
		loading.hide();
	};

	$.fancybox.next = function() {
		return $.fancybox.pos( currentIndex + 1);
	};
	
	$.fancybox.prev = function() {
		return $.fancybox.pos( currentIndex - 1);
	};

	$.fancybox.pos = function(pos) {
		if (busy) {
			return;
		}

		pos = parseInt(pos, 10);

		if (pos > -1 && currentArray.length > pos) {
			selectedIndex = pos;
			fancybox_start();
		}

		if (currentOpts.cyclic && currentArray.length > 1 && pos < 0) {
			selectedIndex = currentArray.length - 1;
			fancybox_start();
		}

		if (currentOpts.cyclic && currentArray.length > 1 && pos >= currentArray.length) {
			selectedIndex = 0;
			fancybox_start();
		}

		return;
	};

	$.fancybox.cancel = function() {
		if (busy) {
			return;
		}

		busy = true;

		$.event.trigger('fancybox-cancel');

		fancybox_abort();

		if (selectedOpts && $.isFunction(selectedOpts.onCancel)) {
			selectedOpts.onCancel(selectedArray, selectedIndex, selectedOpts);
		}

		busy = false;
	};

	// Note: within an iframe use - parent.$.fancybox.close();
	$.fancybox.close = function() {
		if (busy || wrap.is(':hidden')) {
			return;
		}

		busy = true;

		if (currentOpts && $.isFunction(currentOpts.onCleanup)) {
			if (currentOpts.onCleanup(currentArray, currentIndex, currentOpts) === false) {
				busy = false;
				return;
			}
		}

		fancybox_abort();

		$(close.add( nav_left ).add( nav_right )).hide();

		$('#fancybox-title').remove();

		wrap.add(inner).add(overlay).unbind();

		$(window).unbind("resize.fb scroll.fb");
		$(document).unbind('keydown.fb');

		function _cleanup() {
			overlay.fadeOut('fast');

			wrap.hide();

			$.event.trigger('fancybox-cleanup');

			inner.empty();

			if ($.isFunction(currentOpts.onClosed)) {
				currentOpts.onClosed(currentArray, currentIndex, currentOpts);
			}

			currentArray	= selectedOpts	= [];
			currentIndex	= selectedIndex	= 0;
			currentOpts		= selectedOpts	= {};

			busy = false;
		}

		inner.css('overflow', 'hidden');

		if (currentOpts.transitionOut == 'elastic') {
			start_pos = fancybox_get_zoom_from();

			var pos = wrap.position();

			final_pos = {
				top		:	pos.top ,
				left	:	pos.left,
				width	:	wrap.width(),
				height	:	wrap.height()
			};

			if (currentOpts.opacity) {
				final_pos.opacity = 1;
			}

			fx.prop = 1;

			$(fx).animate({ prop: 0 }, {
				 duration	: currentOpts.speedOut,
				 easing		: currentOpts.easingOut,
				 step		: fancybox_draw,
				 complete	: _cleanup
			});

		} else {
			wrap.fadeOut( currentOpts.transitionOut == 'none' ? 0 : currentOpts.speedOut, _cleanup);
		}
	};

	$.fancybox.resize = function() {
		var c, h;
		
		if (busy || wrap.is(':hidden')) {
			return;
		}

		busy = true;

		c = inner.wrapInner("<div style='overflow:auto'></div>").children();
		h = c.height();

		wrap.css({height:	h + (currentOpts.padding * 2) + titleh});
		inner.css({height:	h});

		c.replaceWith(c.children());

		$.fancybox.center();
	};

	$.fancybox.center = function() {
		busy = true;

		var view	= fancybox_get_viewport(),
			margin	= currentOpts.margin,
			to		= {};

		to.top	= view[3] + ((view[1] - ((wrap.height() - titleh) + (shadow * 2 ))) * 0.5);
		to.left	= view[2] + ((view[0] - (wrap.width() + (shadow * 2 ))) * 0.5);

		to.top	= Math.max(view[3] + margin, to.top);
		to.left	= Math.max(view[2] + margin, to.left);

		wrap.css(to);

		busy = false;
	};

	$.fn.fancybox.defaults = {
		padding				:	10,
		margin				:	20,
		opacity				:	false,
		modal				:	false,
		cyclic				:	false,
		scrolling			:	'auto',	// 'auto', 'yes' or 'no'

		width				:	560,
		height				:	340,

		autoScale			:	true,
		autoDimensions		:	true,
		centerOnScroll		:	false,

		ajax				:	{},
		swf					:	{ wmode: 'transparent' },

		hideOnOverlayClick	:	true,
		hideOnContentClick	:	false,

		overlayShow			:	true,
		overlayOpacity		:	0.3,
		overlayColor		:	'#666',

		titleShow			:	true,
		titlePosition		:	'outside',	// 'outside', 'inside' or 'over'
		titleFormat			:	null,

		transitionIn		:	'fade',	// 'elastic', 'fade' or 'none'
		transitionOut		:	'fade',	// 'elastic', 'fade' or 'none'

		speedIn				:	300,
		speedOut			:	300,

		changeSpeed			:	300,
		changeFade			:	'fast',

		easingIn			:	'swing',
		easingOut			:	'swing',

		showCloseButton		:	true,
		showNavArrows		:	true,
		enableEscapeButton	:	true,

		onStart				:	null,
		onCancel			:	null,
		onComplete			:	null,
		onCleanup			:	null,
		onClosed			:	null
	};

	$(document).ready(function() {
		fancybox_init();
	});

})(jQuery);
