/**
* LightGallery v1.3
* Author: Dmitri Ischenko ischenkodv@gmail.com
* Freely distributable under MIT-style license
*/
//var lightgallery=(function(){var h,g,c,a,H,ad,J={showOverlay:true,overlayColor:"#000",overlayOpacity:0.85,zoomStep:0.2,animate:true,framesNumber:20,speed:30,resizeSync:false,enableZoom:true,fadeImage:true,alias:"lightgallery",fullSize:false,minPadding:15},al={next:"Next",prev:"Previous",zoomIn:"Zoom In",zoomOut:"Zoom Out",fullSize:"Full Size",fitScreen:"Fit screen",close:"Close",image:"Image",of:"of"},p,T,Q,s,L,b,k,x,l,aj,d,B,w,ai,af="hidden",am="visible",y="block",U="none",z="opacity",I="left",S="top",i="width",P="height",an="px",A="div",Y=window,R=document,f;var r={setLangVars:function(G){t(al,G)},init:function(at){if(at){t(J,at)}J.fullSize=J.fullSize?1:0;if(!a){return V()}if(/MSIE ([^;]+)/.test(navigator.userAgent)){p=parseFloat(RegExp["$1"])}f=[];var av=R.getElementsByTagName("a"),au=new RegExp("^"+J.alias+"\\[([a-zA-Z]+)\\]|"+J.alias+"$"),ar;for(var aq=0,ap=av.length;aq<ap;aq++){if(av[aq].rel&&(ar=av[aq].rel.match(au))){m(av[aq],"click",r.showImage);if(ar=ar[1]){av[aq].__gallery__=ar;if(!f[ar]){f[ar]=[]}av[aq].__index__=f[ar].push(av[aq])-1}}}var G=R.getElementsByTagName("body")[0];G.appendChild(ai=ao(A,{id:"LG_overlay",events:{click:r.close}}));G.appendChild(T=D());innerCont=T.lastChild;m((G.attachEvent)?G:Y,"keypress",v);(x=ao("img")).onload=function(){e();l.setAttribute("src",x.src);q(J.fullSize,true);o()};g=T.offsetHeight;c=p?200:T.offsetWidth;h=0;ab(ai,{background:(J.overlayColor),display:U});aa(ai,J.overlayOpacity)},open:function(){if(d){return}n();l.style.display=y;q();ab(T,{visibility:am,display:y});d=1},close:function(){M();ab(T,{visibility:af,display:U});d=0;x.src=l.src=""},zoomIn:function(){r.Zoom(1+J.zoomStep)},zoomOut:function(){r.Zoom(1-J.zoomStep)},zoomNormal:function(){if(this.$disabled){return}r.Zoom(l.width==x.width&&l.height==x.height?0:1)},Zoom:function(G){ah();q(G)},showImage:function(ap){var G=this.__index__;N(ap||Y.event);if(this.__gallery__&&G>-1){aj=this.__gallery__;r.show(G)}else{r.showSingle(this)}},showSingle:function(G){r.open();ah();E();x.src=G.href;Q.innerHTML=G.title;b.innerHTML="";s.style.visibility=L.style.visibility=af},show:function(ap){if(ap<0||ap>f[aj].length-1||(J.animate&&ad)){return}r.open();var G=f[aj],aq=L.style,ar=s.style;ah();E();ad=1;x.src=G[ap].href;Q.innerHTML=G[ap].title;b.innerHTML=al.image+" "+(ap+1)+" "+al.of+" "+G.length;B=ap;ac()?aq.visibility=am:aq.visibility=af;u()?ar.visibility=am:ar.visibility=af;Y.focus()},next:function(){r.show(B+1)},prev:function(){r.show(B-1)}};function ac(){return(B<(f[aj].length-1))?true:false}function u(){return(B)?true:false}function o(){var G=f[aj];if(!G){return}if(G[B+1]){(new Image).src=G[B+1].href}if(G[B-1]){(new Image).src=G[B-1].href}}function n(ap){if(J.showOverlay){var G=C();ab(ai,{width:G[0]+"px",height:G[1]+"px"});if(ai.style.display!=y){ab(ai,{display:y});F(ai,{end:J.overlayOpacity*100,onend:ap})}}else{if(typeof ap=="function"){ap.call(this)}}}function M(){ae(ai,{start:J.overlayOpacity*100,onEnd:function(){ai.style.display=U}})}function q(aH,aB){var au,aL,az,aJ,aE=J.minPadding*2,aD=J.framesNumber,aI=x.width,aK=x.height,aF=C(),aq=aF[2],av=aF[3],aw=aq-aE-h,aM=av-aE-g;if(aH==0||(aB&&!aH)){if(aI>aw||aK>aM){var aA=aw,aG=aw*aK/aI;if(aG>aM){aG=aM;aA=aM*aI/aK}az=(l.width=aA)+h;aJ=(l.height=aG)+g}else{az=(l.width=aI)+h;aJ=(l.height=aK)+g}}else{if(aH==1){az=(l.width=aI)+h;aJ=(l.height=aK)+g}else{if(aH<1||aH>1){az=(l.width*=aH)+h;aJ=(l.height*=aH)+g}else{az=aJ=300;var ap=true}}}if(au=(az>(aw+h)||aJ>(aM+g))){aL=al.fitScreen;fsClass="LG_fitScreen"}else{if(l.width!=aI||l.height!=aK){aL=al.fullSize;fsClass="LG_zoomNormal"}}k.$disabled=false;if(l.width==aI){if(au){k.id=fsClass;k.setAttribute("title",aL)}else{k.id="LG_zoom_disabled";k.$disabled=true}}else{k.id="LG_zoomNormal";k.setAttribute("title",al.fullSize)}az=Math.max(az,c);var aN=W(),ax=(av>aJ?(av-aJ)/2:J.minPadding)+aN[1],ay=(aq>az?(aq-az)/2:J.minPadding)+aN[0],aC=(az/3)+"px",G=(aJ-g-10)+"px";ab(L,{width:aC,height:G});ab(s,{width:aC,height:G});if(J.animate&&!ap){var at=new K(T,aD,J.speed);if(J.resizeSync){at.addThread(i,0,az,0,aD).addThread(I,0,ay,0,aD).addThread(P,0,aJ,0,aD).addThread(S,0,ax,0,aD)}else{var aO=Math.ceil(aD/2);at.addThread(i,0,az,0,aO).addThread(I,0,ay,0,aO).addThread(P,0,aJ,aO,aD).addThread(S,0,ax,aO,aD)}at.onEnd=function(){n();O()};at.run()}else{ab(T,{top:ax+an,left:ay+an,width:az+an,height:aJ+an});n();O()}}function O(){innerCont.style.display=y;if(J.fadeImage){F(l,{frames:8,speed:J.speed,onEnd:function(){ad=0}})}else{aa(l,100);ad=0}}function ah(){innerCont.style.display=U}function E(){w.style.display=y}function e(){w.style.display=U}function D(){var ap,G;if(J.enableZoom){ap=ao(A,{id:"LG_zoomIn",title:al.zoomIn,events:{click:r.zoomIn}});G=ao(A,{id:"LG_zoomOut",title:al.zoomOut,events:{click:r.zoomOut}})}return ao(A,{id:"LG_container"},w=ao(A,{id:"LG_loading"}),ao(A,{id:"LG_innerCont"},ao(A,{id:"LG_panel"},ap,G,k=ao(A,{id:"LG_zoomNormal",title:al.fullSize,events:{click:r.zoomNormal}}),b=ao(A,{id:"LG_imgIndex"},al.image+" 20 "+al.of+" 20 "),ao(A,{id:"LG_closeBtn",title:al.close,events:{click:r.close}}),ao(A,{style:"clear:both"})),l=ao("img",{id:"LG_pic",width:300,height:300}),Q=ao(A,{id:"LG_titleBar"}),s=ao(A,{id:"LG_prevLink",title:al.prev,events:{click:r.prev,mouseover:Z,mouseout:ag}}),L=ao(A,{id:"LG_nextLink",title:al.next,events:{click:r.next,mouseover:Z,mouseout:ag}})))}function v(ap){if(!d){return}var ap=ap||Y.event,G=ap.keyCode?ap.keyCode:(ap.which?ap.which:ap.charCode);switch(G){case 110:r.next();break;case 98:r.prev();break;case 102:r.zoomNormal();break;case 43:r.zoomIn();break;case 45:r.zoomOut();break;case 27:r.close();default:return}N(ap)}function Z(){F(this)}function ag(){ae(this)}function F(ap,G){G=G||{};G.start=G.start||0;G.end=G.end||100;ak(ap,G)}function ae(ap,G){G=G||{};G.start=G.start||100;G.end=G.end||0;ak(ap,G)}function ak(aq,ap){if(J.animate){var G=new K(aq,ap.frames||5,ap.speed||40);G.addThread(z,ap.start,ap.end);G.onStart=ap.onStart;G.onEnd=ap.onEnd;G.run()}else{aa(aq,ap.end);if(typeof ap.onEnd=="function"){ap.onEnd()}}}function N(G){if(G.preventDefault){G.preventDefault()}else{G.returnValue=false}}function m(aq,ap,G){if(Y.addEventListener){m=function(au,at,ar){au.addEventListener(at,ar,false)}}else{if(Y.attachEvent){m=function(au,at,ar){var av=function(){ar.call(au,Y.event)};au.attachEvent("on"+at,av)}}}return m(aq,ap,G)}function t(aq,ap){for(var G in ap){aq[G]=ap[G]}}function ab(ap,G){if(ap){t(ap.style,G)}}function C(){var ar,ap,aq,au,G=R.body,at=R.documentElement;if(Y.innerHeight&&Y.scrollMaxY){ar=G.scrollWidth;ap=Y.innerHeight+Y.scrollMaxY}else{if(G.scrollHeight>G.offsetHeight){ar=G.scrollWidth;ap=G.scrollHeight}else{if(at&&at.scrollHeight>at.offsetHeight){ar=at.scrollWidth;ap=at.scrollHeight}else{ar=G.offsetWidth;ap=G.offsetHeight}}}if(Y.innerHeight){aq=Y.innerWidth;au=Y.innerHeight}else{if(at&&at.clientHeight){aq=at.clientWidth;au=at.clientHeight}else{if(G){aq=G.clientWidth;au=G.clientHeight}}}return[ar<aq?aq:ar,ap<au?au:ap,aq,au]}function W(){var aq=0,ap=0,G=R.body,ar=R.documentElement;if(typeof(Y.pageYOffset)=="number"){ap=Y.pageYOffset;aq=Y.pageXOffset}else{if(G&&(G.scrollLeft||G.scrollTop)){ap=G.scrollTop;aq=G.scrollLeft}else{if(ar&&(ar.scrollLeft||ar.scrollTop)){ap=ar.scrollTop;aq=ar.scrollLeft}}}return[aq,ap]}function X(aq,G){var ar=R.defaultView;if(aq.style[G]){return aq.style[G]}else{if(aq.currentStyle){return aq.currentStyle[G]}else{if(ar&&ar.getComputedStyle){G=G.replace(/([A-Z])/g,"-$1");var ap=ar.getComputedStyle(aq,"");return ap&&ap.getPropertyValue(G.toLowerCase())}}}return null}function aa(){aa=arguments[0].filters?function(G,ap){G.style.filter="alpha(opacity="+ap+")"}:function(G,ap){G.style.opacity=ap/100};aa(arguments[0],arguments[1])}function ao(aq,ap){var av=R.createElement(aq);if(ap){for(var at in ap){if(at=="events"){for(var ar in ap[at]){m(av,ar,ap[at][ar])}}else{var aw=ap[at];if(typeof aw!="undefined"){if(at=="class"){av.className=aw}else{av.setAttribute(at,aw)}}}}}for(var au=2,G=arguments.length;au<G;au++){switch(typeof arguments[au]){case"string":av.innerHTML+=arguments[au];break;case"object":av.appendChild(arguments[au])}}return av}function j(){if(!H){if(!R.body){return setTimeout(j,13)}H=true;r.init()}}function V(){if(a){return}a=true;if(R.readyState==="complete"){return j()}if(R.addEventListener){R.addEventListener("DOMContentLoaded",function ap(){R.removeEventListener("DOMContentLoaded",ap,false);j()},false)}else{if(R.attachEvent){R.attachEvent("onreadystatechange",function at(){if(document.readyState==="complete"){R.detachEvent("onreadystatechange",at);j()}});var aq=false;try{aq=Y.frameElement==null}catch(ar){}if(R.documentElement.doScroll&&aq){function G(){if(H){return}try{R.documentElement.doScroll("left")}catch(au){setTimeout(G,1);return}j()}G()}}}}function K(aq,ap,G){if(!aq){return null}this.E=aq;this.N=ap||0;this.F=[];this.S=G||10}K.prototype={addThread:function(at,aq,G,ar,ap){if(!at||G===undefined||G===null){return}if(at!=z){aq=parseFloat(X(this.E,at))}ar=ar||0;ap=ap||this.N;var aw=this.F,av=(ap-ar)||1,au=(aq-G)/av;for(;ar<ap;ar++){if(!aw[ar]){aw[ar]={}}aw[ar][at]=(aq-=au)}return this},P:function(){var ar=this.F.shift(),ap=[],aq=p;if(ar){for(var G in ar){ap.push(G=="opacity"?(aq?"filter: alpha(opacity="+ar[G]+")":"opacity: "+ar[G]/100):G+": "+ar[G]+"px")}this.E.style.cssText+="; "+ap.join("; ")}else{if(typeof this.onEnd=="function"){this.onEnd()}clearInterval(this.I)}},run:function(){clearInterval(this.I);this.P();if(typeof this.onStart=="function"){this.onStart()}var G=this;if(this.N>1){this.I=setInterval(function(){G.P()},this.S)}}};return r})();


var lightgallery = (function () {

    // local variables
    var dx,
	dy,
	minContainerWidth,
	readyBound,
	isReady,
	bInProgress,

    // Library options
	options = {
	    showOverlay: true,
	    overlayColor: '#000',
	    overlayOpacity: .85,
	    zoomStep: .2,
	    animate: true,
	    framesNumber: 20,
	    speed: 30,
	    resizeSync: false, // resize container both vertically and horizontally at the same time
	    enableZoom: true,
	    fadeImage: true,
	    alias: 'lightgallery',
	    fullSize: false,
	    minPadding: 15		// minimal distance between container and window
	},

    // Language variables
	langVars = {
	    /*
	    next	: 'Next',
	    prev	: 'Previous',
	    zoomIn	: 'Zoom In',
	    zoomOut	: 'Zoom Out',
	    fullSize: 'Full Size',
	    fitScreen: 'Fit screen',
	    close	: 'Close',
	    image	: 'Image',
	    of	: 'of'
	    */

	    next: 'Devant',
	    prev: 'Derierre',
	    zoomIn: 'Augmanter',
	    zoomOut: 'Deminuer',
	    fullSize: 'Full Size',
	    fitScreen: 'Sur tout l\'ecran',
	    close: 'Fermer',
	    image: 'l\'image',
	    of: 'de'
	},

    // If Internet Explorer
	isIE,

    /* container and its elements */
	container, 	// container which holds image;
	titleBar, 	// title bar
	prevBtn, 	// "previous" button
	nextBtn, 	// "next" button
	imgIndex, 	// index of images
	fullSizeBtn, // button which show image full size

	loaderImage, // image loader
	picture, 	// image
	gallery,
	isOpen, 		// if gallery open?
	current, 	// index of the current image showing
	oThrobber, 	// Throbber

    /* Reference to overlay */
	overlay,

    /* constants */
	HIDDEN = 'hidden',
	VISIBLE = 'visible',
	BLOCK = 'block',
	NONE = 'none',
	OPACITY = 'opacity',
	LEFT = 'left',
	TOP = 'top',
	WIDTH = 'width',
	HEIGHT = 'height',
	PX = 'px',
	DIV = 'div',
	WND = window,
	DOC = document,

	images; // list of images

    var G = {

        /**
        * Set language variables
        * @param {Object} vars - language variables
        */
        setLangVars: function (vars) {
            extend(langVars, vars);
        },


        /**
        * Initialize gallery
        * @param {object} opts - gallery options
        */
        init: function (opts) {

            if (opts) {
                extend(options, opts);
            }
            options.fullSize = options.fullSize ? 1 : 0;

            if (!readyBound) return bindReady();

            // detect engine
            if (/MSIE ([^;]+)/.test(navigator.userAgent)) {
                isIE = parseFloat(RegExp["$1"]);
            }


            // get images
            images = [];
            var imgs = DOC.getElementsByTagName('a'),
			regx = new RegExp('^' + options.alias + '\\[([a-zA-Z]+)\\]|' + options.alias + '$'),
			r; 	// variable to hold RegEx matches

            // filter images that match specified RegEx expression
            for (var i = 0, len = imgs.length; i < len; i++) {
                if (imgs[i].rel && (r = imgs[i].rel.match(regx))) {
                    addEvent(imgs[i], 'click', G.showImage);
                    if (r = r[1]) {
                        // save gallery name in image
                        imgs[i].__gallery__ = r;

                        if (!images[r]) {
                            images[r] = [];
                        }

                        imgs[i].__index__ = images[r].push(imgs[i]) - 1;
                    }
                }
            }

            // create overlay and container and add it to body
            var b = DOC.getElementsByTagName('body')[0];

            b.appendChild(overlay = _(DIV, {
                id: 'LG_overlay',
                events: { click: G.close }
            })
		);

            b.appendChild(container = createContainer());
            innerCont = container.lastChild;

            addEvent(
			(b.attachEvent) ? b : WND,
			'keypress',
			keyPressHandler
		);

            // create new Image element to load images
            (loaderImage = _('img')).onload = function () {
                hideLoadingIcon();

                picture.setAttribute("src", loaderImage.src);
                setContPos(options.fullSize, true);
                preload();
            }

            // define the difference between container and image size
            dy = container.offsetHeight;
            minContainerWidth = isIE ? 200 : container.offsetWidth;
            dx = 0;

            // set default color and opacity for overlay
            css(overlay, {
                background: (options.overlayColor),
                display: NONE
            });
            setOpacity(overlay, options.overlayOpacity);
        },

        /**
        * Open (show) gallery
        */
        open: function () {
            if (isOpen) return;

            showOverlay();

            // display container
            picture.style.display = BLOCK;
            setContPos();
            css(container, { visibility: VISIBLE, display: BLOCK });
            isOpen = 1;
        },

        /**
        * Close gallery
        */
        close: function () {
            hideOverlay();
            css(container, { visibility: HIDDEN, display: NONE });
            isOpen = 0;

            loaderImage.src = picture.src = '';
        },

        zoomIn: function () {
            G.Zoom(1 + options.zoomStep);
        },

        zoomOut: function () {
            G.Zoom(1 - options.zoomStep);
        },

        zoomNormal: function () {
            if (this.$disabled)
                return;

            G.Zoom(
			picture.width == loaderImage.width && picture.height == loaderImage.height ? 0 : 1
		);
        },

        Zoom: function (coef) {
            hideContent();
            setContPos(coef)
        },

        /**
        * Shows image when user click it
        * @param {Object} e - event object
        */
        showImage: function (e) {
            var i = this.__index__;
            stopDefault(e || WND.event);

            if (this.__gallery__ && i > -1) {
                gallery = this.__gallery__;
                G.show(i);
            } else {
                G.showSingle(this);
            }
        },

        /**
        * Show single image
        * @param {Element} elem - reference to element
        */
        showSingle: function (elem) {
            G.open();

            // Hide content and show loading icon
            hideContent();
            showLoadingIcon();

            loaderImage.src = elem.href;

            titleBar.innerHTML = elem.title;
            imgIndex.innerHTML = '';
            prevBtn.style.visibility = nextBtn.style.visibility = HIDDEN;
        },

        /**
        * Show image from the gallery
        * @param {Number} index - index of the image
        */
        show: function (index) {
            if (index < 0 || index > images[gallery].length - 1 || (options.animate && bInProgress))
                return;

            G.open();

            var gal = images[gallery],
			ns = nextBtn.style,
			ps = prevBtn.style;

            hideContent();
            showLoadingIcon();

            bInProgress = 1;

            loaderImage.src = gal[index].href;
            titleBar.innerHTML = gal[index].title;
            imgIndex.innerHTML = langVars.image + ' ' + (index + 1) + ' ' + langVars.of + ' ' + gal.length;

            current = index;

            // show or hide prev/next buttons depending on image index
            hasNext() ? ns.visibility = VISIBLE : ns.visibility = HIDDEN;
            hasPrev() ? ps.visibility = VISIBLE : ps.visibility = HIDDEN;

            WND.focus();
        },

        // show next image
        next: function () {
            G.show(current + 1);
        },

        // show previous image
        prev: function () {
            G.show(current - 1);
        }
    }

    /**
    * Detects if gallery has next image after current
    */
    function hasNext() {
        return (current < (images[gallery].length - 1)) ? true : false;
    }

    /**
    * Detects if gallery has previous image before current
    */
    function hasPrev() {
        return (current) ? true : false;
    }

    /**
    * Preload adjacent images
    */
    function preload() {
        var gal = images[gallery];
        if (!gal) return;
        if (gal[current + 1]) (new Image).src = gal[current + 1].href;
        if (gal[current - 1]) (new Image).src = gal[current - 1].href;
    }


    /**
    * Set the size and position of the container
    * @param callback {Function}
    */
    function showOverlay(callback) {
        if (options.showOverlay) {

            // set overlay size
            var ar = getPageSize();
            css(overlay, {
                width: ar[0] + "px",
                height: ar[1] + "px"
            });

            // show overlay if it's not shown already
            if (overlay.style.display != BLOCK) {
                css(overlay, { display: BLOCK });
                fadeIn(overlay, { end: options.overlayOpacity * 100, onend: callback });
            }
        } else {
            if (typeof callback == 'function') {
                callback.call(this);
            }
        }
    }

    /**
    * Hides overlay
    */
    function hideOverlay() {
        fadeOut(overlay, {
            start: options.overlayOpacity * 100,
            onEnd: function () {
                overlay.style.display = NONE;
            }
        });
    }

    /**
    * Set container position
    * @param {number} vScale
    * @param {boolean} bIsOnload - show if function is called from whithin onload event
    */
    function setContPos(vScale, bIsOnload) {
        // define references and variables
        var notFitScreen, fsTitle,
		w, h, // width and height of the container
		padding = options.minPadding * 2,
		framesNumber = options.framesNumber,

        // size of the container plus padding
		dLoadWidth = loaderImage.width,
		dLoadHeight = loaderImage.height,

        // size of the viewport and the space available to the container
		ar = getPageSize(),
		dScreenWidth = ar[2],
		dScreenHeight = ar[3],
		dAvailableWidth = dScreenWidth - padding - dx,
		dAvailableHeight = dScreenHeight - padding - dy;

        // *****************************************
        // define width and height of the container
        if (vScale == 0 || (bIsOnload && !vScale)) {
            // set size of the container according to the size of the viewport
            if (dLoadWidth > dAvailableWidth || dLoadHeight > dAvailableHeight) {
                var newWidth = dAvailableWidth,
				newHeight = dAvailableWidth * dLoadHeight / dLoadWidth;

                if (newHeight > dAvailableHeight) {
                    newHeight = dAvailableHeight;
                    newWidth = dAvailableHeight * dLoadWidth / dLoadHeight;
                }

                w = (picture.width = newWidth) + dx;
                h = (picture.height = newHeight) + dy;
            } else {
                w = (picture.width = dLoadWidth) + dx;
                h = (picture.height = dLoadHeight) + dy;
            }

        } else if (vScale == 1) {
            // show image in real size
            w = (picture.width = dLoadWidth) + dx;
            h = (picture.height = dLoadHeight) + dy;
        } else if (vScale < 1 || vScale > 1) {
            // zoom image according to vScale
            w = (picture.width *= vScale) + dx;
            h = (picture.height *= vScale) + dy;
        } else {
            w = h = 300; // default size
            var disableAnimate = true;
        }

        // enable/disable the full size button
        if (notFitScreen = (w > (dAvailableWidth + dx) || h > (dAvailableHeight + dy))) {
            fsTitle = langVars.fitScreen;
            fsClass = 'LG_fitScreen';
        } else if (picture.width != dLoadWidth || picture.height != dLoadHeight) {
            fsTitle = langVars.fullSize;
            fsClass = 'LG_zoomNormal';
        }

        fullSizeBtn.$disabled = false;
        if (picture.width == dLoadWidth) {
            // it is real size of the image
            if (notFitScreen) {
                fullSizeBtn.id = fsClass;
                fullSizeBtn.setAttribute('title', fsTitle);
            } else {
                fullSizeBtn.id = 'LG_zoom_disabled';
                fullSizeBtn.$disabled = true;
            }
        } else {
            fullSizeBtn.id = 'LG_zoomNormal';
            fullSizeBtn.setAttribute('title', langVars.fullSize);
        }

        // here we set the minimal width of the container
        w = Math.max(w, minContainerWidth);

        // correct coords according to scroll bars position
        var scr = getScrollXY(),
		y = (dScreenHeight > h ? (dScreenHeight - h) / 2 : options.minPadding) + scr[1],
		x = (dScreenWidth > w ? (dScreenWidth - w) / 2 : options.minPadding) + scr[0],

        // set the width of the prev/next buttons as 1/3 of the picture width
		dBtnWidth = (w / 3) + 'px',
		dBtnHeight = (h - dy - 10) + 'px';

        css(nextBtn, { width: dBtnWidth, height: dBtnHeight });
        css(prevBtn, { width: dBtnWidth, height: dBtnHeight });

        if (options.animate && !disableAnimate) {
            var anime = new Movie(container, framesNumber, options.speed);
            if (options.resizeSync) {
                anime.addThread(WIDTH, 0, w, 0, framesNumber)
				.addThread(LEFT, 0, x, 0, framesNumber)
				.addThread(HEIGHT, 0, h, 0, framesNumber)
				.addThread(TOP, 0, y, 0, framesNumber);
            } else {
                var middle = Math.ceil(framesNumber / 2);
                anime.addThread(WIDTH, 0, w, 0, middle)
				.addThread(LEFT, 0, x, 0, middle)
				.addThread(HEIGHT, 0, h, middle, framesNumber)
				.addThread(TOP, 0, y, middle, framesNumber);
            }
            anime.onEnd = function () {
                showOverlay();
                showContent();
            };
            anime.run();
        } else {
            css(container, { top: y + PX, left: x + PX, width: w + PX, height: h + PX });
            showOverlay();
            showContent();
        }
    }

    /**
    * Show container content
    */
    function showContent() {
        innerCont.style.display = BLOCK;

        if (options.fadeImage) {
            fadeIn(picture, {
                frames: 8,
                speed: options.speed,
                onEnd: function () {
                    bInProgress = 0;
                }
            });
        } else {
            setOpacity(picture, 100);
            bInProgress = 0;
        }
    }

    /**
    * Hide container content
    */
    function hideContent() {
        innerCont.style.display = NONE;
    }

    function showLoadingIcon() {
        oThrobber.style.display = BLOCK;
    }

    function hideLoadingIcon() {
        oThrobber.style.display = NONE;
    }

    /**
    * Create container
    */
    function createContainer() {
        var zoomIn, zoomOut;
        if (options.enableZoom) {
            zoomIn = _(DIV, {
                id: 'LG_zoomIn',
                title: langVars.zoomIn,
                events: {
                    click: G.zoomIn
                }
            });
            zoomOut = _(DIV, { id: 'LG_zoomOut', title: langVars.zoomOut,
                events: { click: G.zoomOut }
            })
        }
        return _(DIV, { id: 'LG_container' },
			oThrobber = _(DIV, { id: 'LG_loading' }),
			_(DIV, { id: 'LG_innerCont' },
				_(DIV, { id: 'LG_panel' },
						zoomIn, zoomOut,
						fullSizeBtn = _(DIV, { id: 'LG_zoomNormal', title: langVars.fullSize,
						    events: { click: G.zoomNormal }
						}),
						imgIndex = _(DIV, { id: 'LG_imgIndex' }, langVars.image + ' 20 ' + langVars.of + ' 20 '),
						_(DIV, { id: 'LG_closeBtn', title: langVars.close,
						    events: { click: G.close }
						}), _(DIV, { style: 'clear:both' })
					),
					picture = _('img', { id: 'LG_pic', width: 300, height: 300 }),
					titleBar = _(DIV, { id: 'LG_titleBar' }),
					prevBtn = _(DIV, { id: 'LG_prevLink', title: langVars.prev,
					    events: {
					        click: G.prev,
					        mouseover: showBtn,
					        mouseout: hideBtn
					    }
					}),
					nextBtn = _(DIV, { id: 'LG_nextLink', title: langVars.next,
					    events: {
					        click: G.next,
					        mouseover: showBtn,
					        mouseout: hideBtn
					    }
					})
		)
	)
    }

    function keyPressHandler(e) {
        if (!isOpen)
            return;
        var e = e || WND.event,
		code = e.keyCode ? e.keyCode : (e.which ? e.which : e.charCode);

        switch (code) {
            case 110: G.next(); break; 	// n key
            case 98: G.prev(); break; 	// b key
            case 102: G.zoomNormal(); break; // f key
            case 43: G.zoomIn(); break; 	// +
            case 45: G.zoomOut(); break; // -
            case 27: G.close(); 		// Esc key
            default: return;
        }

        stopDefault(e);
    }

    function showBtn() {
        fadeIn(this);
    }

    function hideBtn() {
        fadeOut(this);
    }

    function fadeIn(elem, opts) {
        opts = opts || {};
        opts.start = opts.start || 0;
        opts.end = opts.end || 100;
        fade(elem, opts);
    }
    function fadeOut(elem, opts) {
        opts = opts || {};
        opts.start = opts.start || 100;
        opts.end = opts.end || 0;
        fade(elem, opts);
    }
    function fade(elem, opts) {
        if (options.animate) {
            var a = new Movie(elem, opts.frames || 5, opts.speed || 40);
            a.addThread(OPACITY, opts.start, opts.end);
            a.onStart = opts.onStart;
            a.onEnd = opts.onEnd;
            a.run();
        }
        else {
            setOpacity(elem, opts.end);
            if (typeof opts.onEnd == 'function') opts.onEnd();
        }
    }

    /**
    * Prevent default browser action
    * @param e {event}
    */
    function stopDefault(e) {
        if (e.preventDefault)
            e.preventDefault();
        else
            e.returnValue = false;
    }

    /**
    * Add event listener
    */
    function addEvent(el, type, fn) {
        if (WND.addEventListener) {
            addEvent = function (el, type, fn) {
                el.addEventListener(type, fn, false);
            }
        } else if (WND.attachEvent) {
            addEvent = function (el, type, fn) {
                var f = function () {
                    fn.call(el, WND.event);
                }
                el.attachEvent('on' + type, f);
            }
        }
        return addEvent(el, type, fn);
    }

    /**
    * Extends object with properties of another object
    * @param {object} target
    * @param {object} source
    */
    function extend(target, source) {
        for (var i in source)
            target[i] = source[i];
    }

    /**
    * Set CSS style of the element
    * @param {object} elem
    * @param {object} styles
    */
    function css(elem, styles) {
        if (elem) {
            extend(elem.style, styles);
        }
    }

    /**
    * Get the page and viewport size
    * @return {Array}
    */
    function getPageSize() {
        var xScroll, yScroll, windowWidth, windowHeight, b = DOC.body, de = DOC.documentElement;
        if (WND.innerHeight && WND.scrollMaxY) {
            xScroll = b.scrollWidth;
            yScroll = WND.innerHeight + WND.scrollMaxY;
        } else if (b.scrollHeight > b.offsetHeight) { // all but Explorer Mac
            xScroll = b.scrollWidth;
            yScroll = b.scrollHeight;
        } else if (de && de.scrollHeight > de.offsetHeight) { // Explorer 6 strict mode
            xScroll = de.scrollWidth;
            yScroll = de.scrollHeight;
        } else { // Explorer Mac...would also work in Mozilla and Safari
            xScroll = b.offsetWidth;
            yScroll = b.offsetHeight;
        }

        if (WND.innerHeight) { // all except Explorer
            windowWidth = WND.innerWidth;
            windowHeight = WND.innerHeight;
        } else if (de && de.clientHeight) { // Explorer 6 Strict Mode
            windowWidth = de.clientWidth;
            windowHeight = de.clientHeight;
        } else if (b) { // other Explorers
            windowWidth = b.clientWidth;
            windowHeight = b.clientHeight;
        }


        return [
        // Viewport height. For small pages with total width less then width of the viewport
		xScroll < windowWidth ? windowWidth : xScroll,

        // Viewport height. For small pages with total height less then height of the viewport
		yScroll < windowHeight ? windowHeight : yScroll,

		windowWidth,
		windowHeight
	]
    }

    /**
    * Get coords of scroll bars
    * @return {Array} - [coord horizontal, coord vertical]
    */
    function getScrollXY() {
        var scrOfX = 0, scrOfY = 0, b = DOC.body, de = DOC.documentElement;
        if (typeof (WND.pageYOffset) == 'number') {
            //Netscape compliant
            scrOfY = WND.pageYOffset;
            scrOfX = WND.pageXOffset;
        } else if (b && (b.scrollLeft || b.scrollTop)) {
            //DOM compliant
            scrOfY = b.scrollTop;
            scrOfX = b.scrollLeft;
        } else if (de && (de.scrollLeft || de.scrollTop)) {
            //IE6 Strict
            scrOfY = de.scrollTop;
            scrOfX = de.scrollLeft;
        }
        return [scrOfX, scrOfY];
    }

    /**
    * Get elements style
    * @param {Object} elem - element
    * @param {Object} name - name of the style to get
    */
    function getStyle(elem, name) {
        var d = DOC.defaultView;
        if (elem.style[name])
            return elem.style[name];

        else if (elem.currentStyle)
            return elem.currentStyle[name];

        else if (d && d.getComputedStyle) {
            name = name.replace(/([A-Z])/g, "-$1");

            var s = d.getComputedStyle(elem, "");
            return s && s.getPropertyValue(name.toLowerCase());
        }
        return null;
    }

    /**
    * Cross-browser function to set element opacity
    * @param {Element} elem - element
    * @param {Number} level - level of opacity, percent
    */
    function setOpacity() {
        setOpacity = arguments[0].filters ?
		function (elem, level) { elem.style.filter = "alpha(opacity=" + level + ")" } :
		function (elem, level) { elem.style.opacity = level / 100 }
        setOpacity(arguments[0], arguments[1]);
    }

    /**
    * Create HTML element
    * @param {String} tag - tag name
    * @param {Object} attr - attributes to set, ex: {'name':'someClass',value:'the value'}
    */
    function _(tag, attr) {

        var elem = DOC.createElement(tag);

        if (attr) {
            for (var name in attr) {
                if (name == 'events') {
                    for (var j in attr[name])
                        addEvent(elem, j, attr[name][j]);
                } else {
                    var value = attr[name];
                    if (typeof value != "undefined") {
                        if (name == 'class') {
                            elem.className = value;
                        } else {
                            elem.setAttribute(name, value);
                        }

                    }
                }
            }
        }

        for (var i = 2, len = arguments.length; i < len; i++) {
            switch (typeof arguments[i]) {
                case 'string': elem.innerHTML += arguments[i]; break;
                case 'object': elem.appendChild(arguments[i]);
            }
        }

        return elem;
    }

    /**
    * ondomready functionality from jQuery framework:
    */
    function ready() {
        if (!isReady) {
            if (!DOC.body) {
                return setTimeout(ready, 13);
            }

            isReady = true;

            G.init();
        }
    }

    function bindReady() {
        if (readyBound) return;
        readyBound = true;

        if (DOC.readyState === "complete") {
            return ready();
        }

        if (DOC.addEventListener) {
            DOC.addEventListener("DOMContentLoaded", function DOMContentLoaded() {
                DOC.removeEventListener("DOMContentLoaded", DOMContentLoaded, false);
                ready();
            }, false);

            // If IE event model is used
        } else if (DOC.attachEvent) {
            DOC.attachEvent("onreadystatechange", function onreadystatechange() {
                if (document.readyState === "complete") {
                    DOC.detachEvent("onreadystatechange", onreadystatechange);
                    ready();
                }
            });

            // If IE and not a frame
            // continually check to see if the document is ready
            var toplevel = false;

            try {
                toplevel = WND.frameElement == null;
            } catch (e) { }

            if (DOC.documentElement.doScroll && toplevel) {

                function doScrollCheck() {
                    if (isReady) {
                        return;
                    }

                    try {
                        // If IE is used, use the trick by Diego Perini
                        // http://javascript.nwbox.com/IEContentLoaded/
                        DOC.documentElement.doScroll("left");
                    } catch (e) {
                        setTimeout(doScrollCheck, 1);
                        return;
                    }

                    // and execute any waiting functions
                    ready();
                }

                doScrollCheck();
            }
        }
    }

    /**
    * Class which makes and run animations
    * @param {Element} oElem - target element
    * @param {Number} dNumFrames - number of frames
    * @param {Number} dSpeed - time between each frame, msec
    * @constructor
    */
    function Movie(oElem, dNumFrames, dSpeed) {
        if (!oElem)
            return null;

        this.elem = oElem;
        this.numFrames = dNumFrames || 0;
        this.frames = []; 	// frames array
        this.speed = dSpeed || 10;
    }


    Movie.prototype = {

        /**
        * Add thread - the chain of actions to do on the element
        * @param {String} style - style name
        * @param {Number} startValue - value at the beginning of animation
        * @param {Number} endValue - end value
        * @param {Number} startFrame - frame, from which the animation of thread begin
        * @param {Number} endFrame - frame, which ends the animation
        */
        addThread: function (style, startValue, endValue, startFrame, endFrame) {
            if (!style || endValue === undefined || endValue === null) return;

            if (style != OPACITY)
                startValue = parseFloat(getStyle(this.elem, style));

            startFrame = startFrame || 0;
            endFrame = endFrame || this.numFrames;

            var F = this.frames, 					// reference to frames collection
			count = (endFrame - startFrame) || 1, // number of frames, should be at least 1
			step = (startValue - endValue) / count;

            for (; startFrame < endFrame; startFrame++) {
                if (!F[startFrame])
                    F[startFrame] = {};
                F[startFrame][style] = (startValue -= step);
            }

            return this;
        },

        /**
        * The step - run the next frame
        */
        step: function () {
            var frame = this.frames.shift(),
			styles = [],
			bIsIE = isIE;

            if (frame) {

                for (var i in frame) {
                    styles.push(
					i == 'opacity' ?
							(bIsIE ? 'filter: alpha(opacity=' + frame[i] + ')' : 'opacity: ' + frame[i] / 100)
						: i + ': ' + frame[i] + 'px'
					);
                }

                this.elem.style.cssText += '; ' + styles.join('; ');

            } else {
                if (typeof this.onEnd == 'function')
                    this.onEnd();

                clearInterval(this.interval);
            }
        },

        /**
        * Show the animation
        */
        run: function () {
            clearInterval(this.interval);

            this.step();

            if (typeof this.onStart == 'function')
                this.onStart();

            var that = this;
            if (this.numFrames > 1) {
                this.interval = setInterval(function () {
                    that.step();
                }, this.speed);
            }
        }

    }

    return G;
})();
