text: // Copyright (c) %%year%% by Code Computerlove (http://www.codecomputerlove.com)
  // Licensed under the MIT license
  // version: %%version%%
  
  (function(window, klass, Util, Cache, DocumentOverlay, Carousel, Toolbar, UILayer, ZoomPanRotate){
  	
  	
  	Util.registerNamespace('Code.PhotoSwipe');
  	var PhotoSwipe = window.Code.PhotoSwipe;
  	
  	
  	PhotoSwipe.PhotoSwipeClass = klass({
  		
  		
  		
  		id: null,
  		settings: null,
  		isBackEventSupported: null,
  		backButtonClicked: null,
  		currentIndex: null,
  		originalImages: null,
  		mouseWheelStartTime: null,
  		windowDimensions: null,
  		
  		
  		
  		// Components
  		cache: null,
  		documentOverlay: null,
  		carousel: null,
  		uiLayer: null,
  		toolbar: null,
  		zoomPanRotate: null,
  		
  		
  		
  		// Handlers
  		windowOrientationChangeHandler: null,
  		windowScrollHandler: null,
  		windowHashChangeHandler: null,
  		keyDownHandler: null,
  		windowOrientationEventName: null,
  		uiLayerTouchHandler: null,
  		carouselSlideByEndHandler: null,
  		carouselSlideshowStartHandler: null,
  		carouselSlideshowStopHandler: null,
  		toolbarTapHandler: null,
  		toolbarBeforeShowHandler: null,
  		toolbarShowHandler: null,
  		toolbarBeforeHideHandler: null,
  		toolbarHideHandler: null,
  		mouseWheelHandler: null,
  		zoomPanRotateTransformHandler: null,
  		
  		
  		_isResettingPosition: null,
  		_uiWebViewResetPositionTimeout: null,
  				
  		
  		/*
  		 * Function: dispose
  		 */
  		dispose: function(){
  		
  			var prop;
  			
  			Util.Events.remove(this, PhotoSwipe.EventTypes.onBeforeShow);
  			Util.Events.remove(this, PhotoSwipe.EventTypes.onShow);
  			Util.Events.remove(this, PhotoSwipe.EventTypes.onBeforeHide);
  			Util.Events.remove(this, PhotoSwipe.EventTypes.onHide);
  			Util.Events.remove(this, PhotoSwipe.EventTypes.onDisplayImage);
  			Util.Events.remove(this, PhotoSwipe.EventTypes.onResetPosition);
  			Util.Events.remove(this, PhotoSwipe.EventTypes.onSlideshowStart);
  			Util.Events.remove(this, PhotoSwipe.EventTypes.onSlideshowStop);
  			Util.Events.remove(this, PhotoSwipe.EventTypes.onTouch);
  			Util.Events.remove(this, PhotoSwipe.EventTypes.onBeforeCaptionAndToolbarShow);
  			Util.Events.remove(this, PhotoSwipe.EventTypes.onCaptionAndToolbarShow);
  			Util.Events.remove(this, PhotoSwipe.EventTypes.onBeforeCaptionAndToolbarHide);
  			Util.Events.remove(this, PhotoSwipe.EventTypes.onCaptionAndToolbarHide);
  			Util.Events.remove(this, PhotoSwipe.EventTypes.onZoomPanRotateTransform);
  			
  			
  			this.removeEventHandlers();
  			
  			if (!Util.isNothing(this.documentOverlay)){
  				this.documentOverlay.dispose();
  			}
  			
  			if (!Util.isNothing(this.carousel)){
  				this.carousel.dispose();
  			}
  			
  			this.destroyZoomPanRotate();
  			
  			if (!Util.isNothing(this.uiLayer)){
  				this.uiLayer.dispose();
  			}
  			
  			if (!Util.isNothing(this.toolbar)){
  				this.toolbar.dispose();
  			}
  			
  			if (!Util.isNothing(this.cache)){
  				this.cache.dispose();
  			}
  			
  			for (prop in this) {
  				if (Util.objectHasProperty(this, prop)) {
  					this[prop] = null;
  				}
  			}
  		
  		},
  		
  		
  		
  		/*
  		 * Function: initialize
  		 */
  		initialize: function(images, options, id){
  			
  			var targetPosition;
  			
  			if (Util.isNothing(id)){
  				this.id = 'PhotoSwipe' + new Date().getTime().toString();
  			}
  			else{
  				this.id = id;
  			}
  			
  			this.originalImages = images;
  			
  			if (Util.Browser.android && !Util.Browser.firefox){
  				if (window.navigator.userAgent.match(/Android (\d+.\d+)/).toString().replace(/^.*\,/, '') >= 2.1){
  					this.isBackEventSupported = true;
  				}
  			}
  			
  			if (!this.isBackEventSupported){
  				this.isBackEventSupported = Util.objectHasProperty(window, 'onhashchange');
  			}
  			
  			this.settings = {
  				
  				// General
  				fadeInSpeed: 250,
  				fadeOutSpeed: 250,
  				preventHide: false,
  				preventSlideshow: false,
  				zIndex: 1000,
  				backButtonHideEnabled: true,
  				enableKeyboard: true,
  				enableMouseWheel: true,
  				mouseWheelSpeed: 350,
  				autoStartSlideshow: false,
  				jQueryMobile: ( !Util.isNothing(window.jQuery) && !Util.isNothing(window.jQuery.mobile) ),
  				jQueryMobileDialogHash: '&ui-state=dialog',
  				enableUIWebViewRepositionTimeout: false,
  				uiWebViewResetPositionDelay: 500,
  				target: window,
  				preventDefaultTouchEvents: true,
  				allowVerticalScroll:false,
  				
  				// Carousel
  				loop: true,
  				slideSpeed: 250,
  				nextPreviousSlideSpeed: 0,
  				enableDrag: true,
  				swipeThreshold: 50,
  				swipeTimeThreshold: 250,
  				slideTimingFunction: 'ease-out',
  				slideshowDelay: 3000,
  				doubleTapSpeed: 250,
  				margin: 20,
  				imageScaleMethod: 'fit', // Either "fit", "fitNoUpscale" or "zoom",
  				
  				
  				// Toolbar
  				captionAndToolbarHide: false,
  				captionAndToolbarFlipPosition: false,
  				captionAndToolbarAutoHideDelay: 5000,
  				captionAndToolbarOpacity: 0.8,
  				captionAndToolbarShowEmptyCaptions: true,
  				getToolbar: PhotoSwipe.Toolbar.getToolbar,
  				
  				
  				// ZoomPanRotate
  				allowUserZoom: true, 
  				allowRotationOnUserZoom: false,
  				maxUserZoom: 5.0,
  				minUserZoom: 0.5,
  				doubleTapZoomLevel: 2.5,
  				
  				
  				// Cache
  				getImageSource: PhotoSwipe.Cache.Functions.getImageSource,
  				getImageCaption: PhotoSwipe.Cache.Functions.getImageCaption,
  				getImageMetaData: PhotoSwipe.Cache.Functions.getImageMetaData,
  				cacheMode: PhotoSwipe.Cache.Mode.normal
  				
  			};
  			
  			Util.extend(this.settings, options);
  			
  			if (this.settings.target !== window){
  				targetPosition = Util.DOM.getStyle(this.settings.target, 'position');
  				if (targetPosition !== 'relative' || targetPosition !== 'absolute'){
  					Util.DOM.setStyle(this.settings.target, 'position', 'relative');
  				}
  			}
  			
  			if (this.settings.target !== window){
  				this.isBackEventSupported = false;
  				this.settings.backButtonHideEnabled = false;
  			}
  			else{
  				if (this.settings.preventHide){
  					this.settings.backButtonHideEnabled = false;
  				}
  			}
  			
  			this.cache = new Cache.CacheClass(images, this.settings);
  			
  		},
  		
  		
  		
  		/*
  		 * Function: show
  		 */
  		show: function(obj){
  			
  			var i, j;
  			
  			this._isResettingPosition = false;
  			this.backButtonClicked = false;
  			
  			// Work out what the starting index is
  			if (Util.isNumber(obj)){
  				this.currentIndex = obj;
  			}
  			else{
  				
  				this.currentIndex = -1;
  				for (i=0, j=this.originalImages.length; i<j; i++){
  					if (this.originalImages[i] === obj){
  						this.currentIndex = i;
  						break;
  					}
  				}
  				
  			}
  			
  			if (this.currentIndex < 0 || this.currentIndex > this.originalImages.length-1){
  				throw "Code.PhotoSwipe.PhotoSwipeClass.show: Starting index out of range";
  			}
  			
  			// Store a reference to the current window dimensions
  			// Use this later to double check that a window has actually
  			// been resized.
  			this.isAlreadyGettingPage = this.getWindowDimensions();
  			
  			// Set this instance to be the active instance
  			PhotoSwipe.setActivateInstance(this);
  			
  			this.windowDimensions = this.getWindowDimensions();
  			
  			// Create components
  			if (this.settings.target === window){
  				Util.DOM.addClass(window.document.body, PhotoSwipe.CssClasses.buildingBody);
  			}
  			else{
  				Util.DOM.addClass(this.settings.target, PhotoSwipe.CssClasses.buildingBody);
  			}
  			this.createComponents();
  			
  			Util.Events.fire(this, {
  				type: PhotoSwipe.EventTypes.onBeforeShow,
  				target: this
  			});
  			
  			// Fade in the document overlay
  			this.documentOverlay.fadeIn(this.settings.fadeInSpeed, this.onDocumentOverlayFadeIn.bind(this));
  			
  		},
  		
  		
  		
  		/*
  		 * Function: getWindowDimensions
  		 */
  		getWindowDimensions: function(){
  		
  			return {
  				width: Util.DOM.windowWidth(),
  				height: Util.DOM.windowHeight()
  			};
  		
  		},
  		
  		
  		
  		/*
  		 * Function: createComponents
  		 */
  		createComponents: function(){
  		
  			this.documentOverlay = new DocumentOverlay.DocumentOverlayClass(this.settings);
  			this.carousel = new Carousel.CarouselClass(this.cache, this.settings);
  			this.uiLayer = new UILayer.UILayerClass(this.settings);
  			if (!this.settings.captionAndToolbarHide){
  				this.toolbar = new Toolbar.ToolbarClass(this.cache, this.settings);
  			}
  			
  		},
  		
  		
  		
  		/*
  		 * Function: resetPosition
  		 */
  		resetPosition: function(){
  			
  			if (this._isResettingPosition){
  				return;
  			}
  			
  			var newWindowDimensions = this.getWindowDimensions();
  			if (!Util.isNothing(this.windowDimensions)){
  				if (newWindowDimensions.width === this.windowDimensions.width && newWindowDimensions.height === this.windowDimensions.height){
  					// This was added as a fudge for iOS
  					return;
  				}
  			}
  			
  			this._isResettingPosition = true;
  			
  			this.windowDimensions = newWindowDimensions;
  			
  			this.destroyZoomPanRotate();
  			
  			this.documentOverlay.resetPosition();
  			this.carousel.resetPosition();
  			
  			if (!Util.isNothing(this.toolbar)){
  				this.toolbar.resetPosition();
  			}
  			
  			this.uiLayer.resetPosition();
  			
  			this._isResettingPosition = false;
  			
  			Util.Events.fire(this, {
  				type: PhotoSwipe.EventTypes.onResetPosition,
  				target: this
  			});
  			
  		},
  		
  		
  		
  		/*
  		 * Function: addEventHandler
  		 */
  		addEventHandler: function(type, handler){
  			
  			Util.Events.add(this, type, handler);
  		
  		},
  		
  		
  		
  		/*
  		 * Function: addEventHandlers
  		 */
  		addEventHandlers: function(){
  			
  			if (Util.isNothing(this.windowOrientationChangeHandler)){
  			
  				this.windowOrientationChangeHandler = this.onWindowOrientationChange.bind(this);
  				this.windowScrollHandler = this.onWindowScroll.bind(this);
  				this.keyDownHandler = this.onKeyDown.bind(this);
  				this.windowHashChangeHandler = this.onWindowHashChange.bind(this);
  				this.uiLayerTouchHandler = this.onUILayerTouch.bind(this);
  				this.carouselSlideByEndHandler = this.onCarouselSlideByEnd.bind(this);
  				this.carouselSlideshowStartHandler = this.onCarouselSlideshowStart.bind(this);
  				this.carouselSlideshowStopHandler = this.onCarouselSlideshowStop.bind(this);
  				this.toolbarTapHandler = this.onToolbarTap.bind(this);
  				this.toolbarBeforeShowHandler = this.onToolbarBeforeShow.bind(this);
  				this.toolbarShowHandler = this.onToolbarShow.bind(this);
  				this.toolbarBeforeHideHandler = this.onToolbarBeforeHide.bind(this);
  				this.toolbarHideHandler = this.onToolbarHide.bind(this);
  				this.mouseWheelHandler = this.onMouseWheel.bind(this);
  				this.zoomPanRotateTransformHandler = this.onZoomPanRotateTransform.bind(this);
  				
  			}
  			
  			// Set window handlers
  			if (Util.Browser.android){
  				// For some reason, resize was more stable than orientationchange in Android
  				this.orientationEventName = 'resize';
  			}
  			else if (Util.Browser.iOS && (!Util.Browser.safari)){
  				Util.Events.add(window.document.body, 'orientationchange', this.windowOrientationChangeHandler);
  			}
  			else{
  				var supportsOrientationChange = !Util.isNothing(window.onorientationchange);
  				this.orientationEventName = supportsOrientationChange ? 'orientationchange' : 'resize';
  			}
  			
  			if (!Util.isNothing(this.orientationEventName)){
  				Util.Events.add(window, this.orientationEventName, this.windowOrientationChangeHandler);
  			}
  			if (this.settings.target === window){
  				Util.Events.add(window, 'scroll', this.windowScrollHandler);
  			}
  			
  			if (this.settings.enableKeyboard){
  				Util.Events.add(window.document, 'keydown', this.keyDownHandler);
  			}
  			
  			
  			if (this.isBackEventSupported && this.settings.backButtonHideEnabled){
  					
  				this.windowHashChangeHandler = this.onWindowHashChange.bind(this);
  				
  				if (this.settings.jQueryMobile){
  					window.location.hash = this.settings.jQueryMobileDialogHash;
  				}
  				else{
  					this.currentHistoryHashValue = 'PhotoSwipe' + new Date().getTime().toString();
  					window.location.hash = this.currentHistoryHashValue;
  				}
  								
  				Util.Events.add(window, 'hashchange', this.windowHashChangeHandler);
  			
  			}
  			
  			if (this.settings.enableMouseWheel){
  				Util.Events.add(window, 'mousewheel', this.mouseWheelHandler);
  			}
  			
  			Util.Events.add(this.uiLayer, Util.TouchElement.EventTypes.onTouch, this.uiLayerTouchHandler);
  			Util.Events.add(this.carousel, Carousel.EventTypes.onSlideByEnd, this.carouselSlideByEndHandler);
  			Util.Events.add(this.carousel, Carousel.EventTypes.onSlideshowStart, this.carouselSlideshowStartHandler);
  			Util.Events.add(this.carousel, Carousel.EventTypes.onSlideshowStop, this.carouselSlideshowStopHandler);
  			
  			if (!Util.isNothing(this.toolbar)){
  				Util.Events.add(this.toolbar, Toolbar.EventTypes.onTap, this.toolbarTapHandler);
  				Util.Events.add(this.toolbar, Toolbar.EventTypes.onBeforeShow, this.toolbarBeforeShowHandler);
  				Util.Events.add(this.toolbar, Toolbar.EventTypes.onShow, this.toolbarShowHandler);
  				Util.Events.add(this.toolbar, Toolbar.EventTypes.onBeforeHide, this.toolbarBeforeHideHandler);
  				Util.Events.add(this.toolbar, Toolbar.EventTypes.onHide, this.toolbarHideHandler);
  			}
  		
  		},
  		
  		
  		
  		/*
  		 * Function: removeEventHandlers
  		 */
  		removeEventHandlers: function(){
  			
  			if (Util.Browser.iOS && (!Util.Browser.safari)){
  				Util.Events.remove(window.document.body, 'orientationchange', this.windowOrientationChangeHandler);
  			}
  			
  			if (!Util.isNothing(this.orientationEventName)){
  				Util.Events.remove(window, this.orientationEventName, this.windowOrientationChangeHandler);
  			}
  			
  			Util.Events.remove(window, 'scroll', this.windowScrollHandler);
  			
  			if (this.settings.enableKeyboard){
  				Util.Events.remove(window.document, 'keydown', this.keyDownHandler);
  			}
  			
  			if (this.isBackEventSupported && this.settings.backButtonHideEnabled && this.windowHashChangeHandler !== null){
  				Util.Events.remove(window, 'hashchange', this.windowHashChangeHandler);
  			}
  			
  			if (this.settings.enableMouseWheel){
  				Util.Events.remove(window, 'mousewheel', this.mouseWheelHandler);
  			}
  			
  			if (!Util.isNothing(this.uiLayer)){
  				Util.Events.remove(this.uiLayer, Util.TouchElement.EventTypes.onTouch, this.uiLayerTouchHandler);
  			}
  			
  			if (!Util.isNothing(this.toolbar)){
  				Util.Events.remove(this.carousel, Carousel.EventTypes.onSlideByEnd, this.carouselSlideByEndHandler);
  				Util.Events.remove(this.carousel, Carousel.EventTypes.onSlideshowStart, this.carouselSlideshowStartHandler);
  				Util.Events.remove(this.carousel, Carousel.EventTypes.onSlideshowStop, this.carouselSlideshowStopHandler);
  			}
  			
  			if (!Util.isNothing(this.toolbar)){
  				Util.Events.remove(this.toolbar, Toolbar.EventTypes.onTap, this.toolbarTapHandler);
  				Util.Events.remove(this.toolbar, Toolbar.EventTypes.onBeforeShow, this.toolbarBeforeShowHandler);
  				Util.Events.remove(this.toolbar, Toolbar.EventTypes.onShow, this.toolbarShowHandler);
  				Util.Events.remove(this.toolbar, Toolbar.EventTypes.onBeforeHide, this.toolbarBeforeHideHandler);
  				Util.Events.remove(this.toolbar, Toolbar.EventTypes.onHide, this.toolbarHideHandler);
  			}
  			
  		},
  		
  		
  		
  		
  		/*
  		 * Function: hide
  		 */
  		hide: function(){
  			
  			if (this.settings.preventHide){
  				return;
  			}
  			
  			if (Util.isNothing(this.documentOverlay)){
  				throw "Code.PhotoSwipe.PhotoSwipeClass.hide: PhotoSwipe instance is already hidden";
  			}
  			
  			if (!Util.isNothing(this.hiding)){
  				return;
  			}
  			
  			this.clearUIWebViewResetPositionTimeout();
  			
  			this.destroyZoomPanRotate();
  			
  			this.removeEventHandlers();
  			
  			Util.Events.fire(this, {
  				type: PhotoSwipe.EventTypes.onBeforeHide,
  				target: this
  			});
  			
  			this.uiLayer.dispose();
  			this.uiLayer = null;
  			
  			if (!Util.isNothing(this.toolbar)){
  				this.toolbar.dispose();
  				this.toolbar = null;
  			}
  			
  			this.carousel.dispose();
  			this.carousel = null;
  			
  			Util.DOM.removeClass(window.document.body, PhotoSwipe.CssClasses.activeBody);
  			Util.DOM.removeClass(window.document.getElementsByTagName("html")[0], PhotoSwipe.CssClasses.activeBody);
  			
  			this.documentOverlay.dispose();
  			this.documentOverlay = null;
  			
  			this._isResettingPosition = false;
  			
  			// Deactive this instance
  			PhotoSwipe.unsetActivateInstance(this);
  		
  			Util.Events.fire(this, {
  				type: PhotoSwipe.EventTypes.onHide,
  				target: this
  			});
  			
  			this.goBackInHistory();
  			
  		},
  		
  		
  		
  		/*
  		 * Function: goBackInHistory
  		 */
  		goBackInHistory: function(){
  			
  			if (this.isBackEventSupported && this.settings.backButtonHideEnabled){
  				if ( !this.backButtonClicked ){
  					window.history.back();
  				}
  			}
  			
  		},
  		
  		
  		
  		/*
  		 * Function: play
  		 */
  		play: function(){
  			
  			if (this.isZoomActive()){
  				return;
  			}
  			
  			if (!this.settings.preventSlideshow){
  				if (!Util.isNothing(this.carousel)){
  					if (!Util.isNothing(this.toolbar) && this.toolbar.isVisible){
  						this.toolbar.fadeOut();
  					}
  					this.carousel.startSlideshow();
  				}
  			}
  			
  		},
  		
  		
  		
  		/*
  		 * Function: stop
  		 */
  		stop: function(){
  			
  			if (this.isZoomActive()){
  				return;
  			}
  			
  			if (!Util.isNothing(this.carousel)){
  				this.carousel.stopSlideshow();
  			}
  		
  		},
  		
  		
  		
  		/*
  		 * Function: previous
  		 */
  		previous: function(){
  			
  			if (this.isZoomActive()){
  				return;
  			}
  			
  			if (!Util.isNothing(this.carousel)){
  				this.carousel.previous();
  			}
  		
  		},
  		
  		
  		
  		/*
  		 * Function: next
  		 */
  		next: function(){
  			
  			if (this.isZoomActive()){
  				return;
  			}
  			
  			if (!Util.isNothing(this.carousel)){
  				this.carousel.next();
  			}
  			
  		},
  		
  		
  		
  		/*
  		 * Function: toggleToolbar
  		 */
  		toggleToolbar: function(){
  			
  			if (this.isZoomActive()){
  				return;
  			}
  			
  			if (!Util.isNothing(this.toolbar)){
  				this.toolbar.toggleVisibility(this.currentIndex);
  			}
  			
  		},
  		
  		
  		
  		/*
  		 * Function: fadeOutToolbarIfVisible
  		 */
  		fadeOutToolbarIfVisible: function(){
  		
  			if (!Util.isNothing(this.toolbar) && this.toolbar.isVisible && this.settings.captionAndToolbarAutoHideDelay > 0){
  				this.toolbar.fadeOut();
  			}
  		
  		},
  		
  		
  		
  		/*
  		 * Function: createZoomPanRotate
  		 */
  		createZoomPanRotate: function(){
  			
  			this.stop();
  			
  			if (this.canUserZoom() && !this.isZoomActive()){
  				
  				Util.Events.fire(this, PhotoSwipe.EventTypes.onBeforeZoomPanRotateShow);
  				
  				this.zoomPanRotate = new ZoomPanRotate.ZoomPanRotateClass(
  					this.settings, 
  					this.cache.images[this.currentIndex],
  					this.uiLayer
  				);
  				
  				// If we don't override this in the event of false
  				// you will be unable to pan around a zoomed image effectively
  				this.uiLayer.captureSettings.preventDefaultTouchEvents = true;
  				
  				Util.Events.add(this.zoomPanRotate, PhotoSwipe.ZoomPanRotate.EventTypes.onTransform, this.zoomPanRotateTransformHandler);
  				
  				Util.Events.fire(this, PhotoSwipe.EventTypes.onZoomPanRotateShow);
  				
  				if (!Util.isNothing(this.toolbar) && this.toolbar.isVisible){
  					this.toolbar.fadeOut();
  				}
  				
  			}
  		
  		},
  		
  		
  		
  		/*
  		 * Function: destroyZoomPanRotate
  		 */
  		destroyZoomPanRotate: function(){
  			
  			if (!Util.isNothing(this.zoomPanRotate)){
  				
  				Util.Events.fire(this, PhotoSwipe.EventTypes.onBeforeZoomPanRotateHide);
  			
  				Util.Events.remove(this.zoomPanRotate, PhotoSwipe.ZoomPanRotate.EventTypes.onTransform, this.zoomPanRotateTransformHandler);
  				this.zoomPanRotate.dispose();
  				this.zoomPanRotate = null;
  				
  				// Set the preventDefaultTouchEvents back to it was
  				this.uiLayer.captureSettings.preventDefaultTouchEvents = this.settings.preventDefaultTouchEvents;
  				
  				Util.Events.fire(this, PhotoSwipe.EventTypes.onZoomPanRotateHide);
  				
  			}
  		
  		},
  		
  		
  		
  		/*
  		 * Function: canUserZoom
  		 */
  		canUserZoom: function(){
  			
  			var testEl, cacheImage;
  			
  			if (Util.Browser.msie){
  				testEl = document.createElement('div');
  				if (Util.isNothing(testEl.style.msTransform)){
  					return false;
  				}
  			}
  			else if (!Util.Browser.isCSSTransformSupported){
  				return false;
  			}
  			
  			if (!this.settings.allowUserZoom){
  				return false;
  			}
  			
  			
  			if (this.carousel.isSliding){
  				return false;
  			}
  			
  			cacheImage = this.cache.images[this.currentIndex];
  			
  			if (Util.isNothing(cacheImage)){
  				return false;
  			}
  			
  			if (cacheImage.isLoading){
  				return false;
  			}
  			
  			return true;
  			
  		},
  		
  		
  		
  		/*
  		 * Function: isZoomActive
  		 */
  		isZoomActive: function(){
  		
  			return (!Util.isNothing(this.zoomPanRotate));
  		
  		},
  		
  		
  		
  		/*
  		 * Function: getCurrentImage
  		 */
  		getCurrentImage: function(){
  		
  			return this.cache.images[this.currentIndex];
  		
  		},
  		
  		
  		
  		/*
  		 * Function: onDocumentOverlayFadeIn
  		 */
  		onDocumentOverlayFadeIn: function(e){
  			
  			window.setTimeout(function(){
  				if (Util.isNothing(this.settings)){
  					return;
  				}
  				
  				var el = (this.settings.target === window) ? window.document.body : this.settings.target;
  				
  				Util.DOM.removeClass(el, PhotoSwipe.CssClasses.buildingBody);
                                  Util.DOM.addClass(window.document.getElementsByTagName("html")[0], PhotoSwipe.CssClasses.activeBody);
  				Util.DOM.addClass(el, PhotoSwipe.CssClasses.activeBody);
  				
  				this.addEventHandlers();
  				
  				this.carousel.show(this.currentIndex);
  				
  				this.uiLayer.show();
  				
  				if (this.settings.autoStartSlideshow){
  					this.play();
  				}
  				else if (!Util.isNothing(this.toolbar)){
  					this.toolbar.show(this.currentIndex);
  				}
  				
  				Util.Events.fire(this, {
  					type: PhotoSwipe.EventTypes.onShow,
  					target: this
  				});
  			
  				this.setUIWebViewResetPositionTimeout();
  				
  			}.bind(this), 250);
  			
  			
  		},
  		
  		
  		
  		/*
  		 * Function: setUIWebViewResetPositionTimeout
  		 */
  		setUIWebViewResetPositionTimeout: function(){
  			
  			if (!this.settings.enableUIWebViewRepositionTimeout){
  				return;
  			}
  			
  			if (!(Util.Browser.iOS && (!Util.Browser.safari))){
  				return;
  			}
  			
  			if (!Util.isNothing(this._uiWebViewResetPositionTimeout)){
  				window.clearTimeout(this._uiWebViewResetPositionTimeout);
  			}
  			this._uiWebViewResetPositionTimeout = window.setTimeout(function(){
  				
  				this.resetPosition();
  				
  				this.setUIWebViewResetPositionTimeout();
  				
  			}.bind(this), this.settings.uiWebViewResetPositionDelay);
  			
  		},
  		
  		
  		
  		/*
  		 * Function: clearUIWebViewResetPositionTimeout
  		 */
  		clearUIWebViewResetPositionTimeout: function(){
  			if (!Util.isNothing(this._uiWebViewResetPositionTimeout)){
  				window.clearTimeout(this._uiWebViewResetPositionTimeout);
  			}
  		},
  		
  		
  		
  		/*
  		 * Function: onWindowScroll
  		 */
  		onWindowScroll: function(e){
  			
  			this.resetPosition();
  		
  		},
  		
  		
  		
  		/*
  		 * Function: onWindowOrientationChange
  		 */
  		onWindowOrientationChange: function(e){
  			
  			this.resetPosition();
  			
  		},
  		
  		
  		
  		/*
  		 * Function: onWindowHashChange
  		 */
  		onWindowHashChange: function(e){
  			
  			var compareHash = '#' + 
  				((this.settings.jQueryMobile) ? this.settings.jQueryMobileDialogHash : this.currentHistoryHashValue);
  			
  			if (window.location.hash !== compareHash){
  				this.backButtonClicked = true;
  				this.hide();
  			}
  		
  		},
  		
  		
  		
  		/*
  		 * Function: onKeyDown
  		 */
  		onKeyDown: function(e){
  			
  			if (e.keyCode === 37) { // Left
  				e.preventDefault();
  				this.previous();
  			}
  			else if (e.keyCode === 39) { // Right
  				e.preventDefault();
  				this.next();
  			}
  			else if (e.keyCode === 38 || e.keyCode === 40) { // Up and down
  				e.preventDefault();
  			}
  			else if (e.keyCode === 27) { // Escape
  				e.preventDefault();
  				this.hide();
  			}
  			else if (e.keyCode === 32) { // Spacebar
  				if (!this.settings.hideToolbar){
  					this.toggleToolbar();
  				}
  				else{
  					this.hide();
  				}
  				e.preventDefault();
  			}
  			else if (e.keyCode === 13) { // Enter
  				e.preventDefault();
  				this.play();
  			}
  			
  		},
  		
  		
  		
  		/*
  		 * Function: onUILayerTouch
  		 */
  		onUILayerTouch: function(e){
  			
  			if (this.isZoomActive()){
  				
  				switch (e.action){
  					
  					case Util.TouchElement.ActionTypes.gestureChange:
  						this.zoomPanRotate.zoomRotate(e.scale, (this.settings.allowRotationOnUserZoom) ? e.rotation : 0);
  						break;
  					
  					case Util.TouchElement.ActionTypes.gestureEnd:
  						this.zoomPanRotate.setStartingScaleAndRotation(e.scale, (this.settings.allowRotationOnUserZoom) ? e.rotation : 0);
  						break;
  						
  					case Util.TouchElement.ActionTypes.touchStart:
  						this.zoomPanRotate.panStart(e.point);
  						break;
  					
  					case Util.TouchElement.ActionTypes.touchMove:
  						this.zoomPanRotate.pan(e.point);
  						break;
  						
  					case Util.TouchElement.ActionTypes.doubleTap:
  						this.destroyZoomPanRotate();
  						this.toggleToolbar();
  						break;
  					
  					case Util.TouchElement.ActionTypes.swipeLeft:
  						this.destroyZoomPanRotate();
  						this.next();
  						this.toggleToolbar();
  						break;
  						
  					case Util.TouchElement.ActionTypes.swipeRight:
  						this.destroyZoomPanRotate();
  						this.previous();
  						this.toggleToolbar();
  						break;
  				}
  			
  			}
  			else{
  				
  				switch (e.action){
  					
  					case Util.TouchElement.ActionTypes.touchMove:
  					case Util.TouchElement.ActionTypes.swipeLeft:
  					case Util.TouchElement.ActionTypes.swipeRight:
  						
  						// Hide the toolbar if need be 
  						this.fadeOutToolbarIfVisible();
  						
  						// Pass the touch onto the carousel
  						this.carousel.onTouch(e.action, e.point);
  						break;
  					
  					case Util.TouchElement.ActionTypes.touchStart:
  					case Util.TouchElement.ActionTypes.touchMoveEnd:
  					
  						// Pass the touch onto the carousel
  						this.carousel.onTouch(e.action, e.point);
  						break;
  						
  					case Util.TouchElement.ActionTypes.tap:
  						this.toggleToolbar();
  						break;
  						
  					case Util.TouchElement.ActionTypes.doubleTap:
  						
  						// Take into consideration the window scroll
  						if (this.settings.target === window){
  							e.point.x -= Util.DOM.windowScrollLeft();
  							e.point.y -= Util.DOM.windowScrollTop();
  						}
  						
  						// Just make sure that if the user clicks out of the image
  						// that the image does not pan out of view!
  						var 
  							cacheImageEl = this.cache.images[this.currentIndex].imageEl,
  						
  							imageTop = window.parseInt(Util.DOM.getStyle(cacheImageEl, 'top'), 10),
  							imageLeft = window.parseInt(Util.DOM.getStyle(cacheImageEl, 'left'), 10),
  							imageRight = imageLeft + Util.DOM.width(cacheImageEl),
  							imageBottom = imageTop + Util.DOM.height(cacheImageEl);
  						
  						if (e.point.x < imageLeft){
  							e.point.x = imageLeft;
  						}
  						else if (e.point.x > imageRight){
  							e.point.x = imageRight;
  						}
  						
  						if (e.point.y < imageTop){
  							e.point.y = imageTop;
  						}
  						else if (e.point.y > imageBottom){
  							e.point.y = imageBottom;
  						}
  						
  						this.createZoomPanRotate();
  						if (this.isZoomActive()){
  							this.zoomPanRotate.zoomAndPanToPoint(this.settings.doubleTapZoomLevel, e.point);
  						}
  						
  						break;
  					
  					case Util.TouchElement.ActionTypes.gestureStart:
  						this.createZoomPanRotate();
  						break;
  				}
  				
  				
  			}
  			
  			Util.Events.fire(this, {
  				type: PhotoSwipe.EventTypes.onTouch,
  				target: this,
  				point: e.point, 
  				action: e.action
  			});
  			
  		},
  		
  		
  		
  		/*
  		 * Function: onCarouselSlideByEnd
  		 */
  		onCarouselSlideByEnd: function(e){
  			
  			this.currentIndex = e.cacheIndex;
  			
  			if (!Util.isNothing(this.toolbar)){
  				this.toolbar.setCaption(this.currentIndex);
  				this.toolbar.setToolbarStatus(this.currentIndex);
  			}
  			
  			Util.Events.fire(this, {
  				type: PhotoSwipe.EventTypes.onDisplayImage,
  				target: this,
  				action: e.action,
  				index: e.cacheIndex
  			});
  		
  		},
  		
  		
  		
  		/*
  		 * Function: onToolbarTap
  		 */
  		onToolbarTap: function(e){
  		
  			switch(e.action){
  				
  				case Toolbar.ToolbarAction.next:
  					this.next();
  					break;
  				
  				case Toolbar.ToolbarAction.previous:
  					this.previous();
  					break;
  					
  				case Toolbar.ToolbarAction.close:
  					this.hide();
  					break;
  				
  				case Toolbar.ToolbarAction.play:
  					this.play();
  					break;
  					
  			}
  			
  			Util.Events.fire(this, { 
  				type: PhotoSwipe.EventTypes.onToolbarTap, 
  				target: this,
  				toolbarAction: e.action,
  				tapTarget: e.tapTarget
  			});
  			
  		},
  		
  		
  		
  		/*
  		 * Function: onMouseWheel
  		 */
  		onMouseWheel: function(e){
  			
  			var 
  				delta = Util.Events.getWheelDelta(e),
  				dt = e.timeStamp - (this.mouseWheelStartTime || 0);
  			
  			if (dt < this.settings.mouseWheelSpeed) {
  				return;
  			}
  			
  			this.mouseWheelStartTime = e.timeStamp;
  			
  			if (this.settings.invertMouseWheel){
  				delta = delta * -1;
  			}
  			
  			if (delta < 0){
  				this.next();
  			}
  			else if (delta > 0){
  				this.previous();
  			}
  			
  		},
  		
  		
  		
  		/*
  		 * Function: onCarouselSlideshowStart
  		 */
  		onCarouselSlideshowStart: function(e){
  		
  			Util.Events.fire(this, {
  				type: PhotoSwipe.EventTypes.onSlideshowStart,
  				target: this
  			});
  		
  		},
  		
  		
  		
  		/*
  		 * Function: onCarouselSlideshowStop
  		 */
  		onCarouselSlideshowStop: function(e){
  		
  			Util.Events.fire(this, {
  				type: PhotoSwipe.EventTypes.onSlideshowStop,
  				target: this
  			});
  		
  		},
  		
  		
  		
  		/*
  		 * Function: onToolbarBeforeShow
  		 */
  		onToolbarBeforeShow: function(e){
  		
  			Util.Events.fire(this, {
  				type: PhotoSwipe.EventTypes.onBeforeCaptionAndToolbarShow,
  				target: this
  			});
  		
  		},
  		
  		
  		
  		/*
  		 * Function: onToolbarShow
  		 */
  		onToolbarShow: function(e){
  		
  			Util.Events.fire(this, {
  				type: PhotoSwipe.EventTypes.onCaptionAndToolbarShow,
  				target: this
  			});
  		
  		},
  		
  		
  		
  		/*
  		 * Function: onToolbarBeforeHide
  		 */
  		onToolbarBeforeHide: function(e){
  		
  			Util.Events.fire(this, {
  				type: PhotoSwipe.EventTypes.onBeforeCaptionAndToolbarHide,
  				target: this
  			});
  		
  		},
  		
  		
  		
  		/*
  		 * Function: onToolbarHide
  		 */
  		onToolbarHide: function(e){
  		
  			Util.Events.fire(this, {
  				type: PhotoSwipe.EventTypes.onCaptionAndToolbarHide,
  				target: this
  			});
  		
  		},
  		
  		
  		
  		/*
  		 * Function: onZoomPanRotateTransform
  		 */
  		onZoomPanRotateTransform: function(e){
  			
  			Util.Events.fire(this, {
  				target: this,
  				type: PhotoSwipe.EventTypes.onZoomPanRotateTransform,
  				scale: e.scale,
  				rotation: e.rotation,
  				rotationDegs: e.rotationDegs,
  				translateX: e.translateX,
  				translateY: e.translateY
  			});
  			
  		}
  		
  		
  	});
  	
  	
  	
  }
  (
  	window, 
  	window.klass, 
  	window.Code.Util,
  	window.Code.PhotoSwipe.Cache,
  	window.Code.PhotoSwipe.DocumentOverlay,
  	window.Code.PhotoSwipe.Carousel,
  	window.Code.PhotoSwipe.Toolbar,
  	window.Code.PhotoSwipe.UILayer,
  	window.Code.PhotoSwipe.ZoomPanRotate
  ));
  