text: (function() {
  	var Engine = window.Engine = {
  		VERSION: 0.1,
  		GAME_OVER: false,
  
  		options: {
  			state: null,
  			debug: false,
  			log: false,
  			dropbox: false,
  			doubleTime: true
  		},
  
  		init: function(options){
  			this.options = $.extend(
  				this.options,
  				options
  			);
  			this._debug = this.options.debug;
  			this._log = this.options.log;
  
  			window.State = {};
  
  			Engine.disableSelection();
  			$('<div>').attr('id', 'locationSlider').appendTo('#main');
  
  			var menu = $('<div>').addClass('menu').appendTo('body');
  
  			// Register keypress handlers
  			$('body').off('keydown').keydown(Engine.keyDown);
  			$('body').off('keyup').keyup(Engine.keyUp);
  
  			// Register swipe handlers
  			swipeElement = $('#outerSlider');
  			swipeElement.on('swipeleft', Engine.swipeLeft);
  			swipeElement.on('swiperight', Engine.swipeRight);
  			swipeElement.on('swipeup', Engine.swipeUp);
  			swipeElement.on('swipedown', Engine.swipeDown);
  
  			// subscribe to stateUpdates
  			//$.Dispatch('stateUpdate').subscribe(Engine.handleStateUpdates);
  
  			$SM.init();
  			Notifications.init();
  			Events.init();
  			KeyboardInputManager.init();
  			Room.init();
  			Library.init();
  
  			Engine.moveTo(Room);
  			$SM.set('wakeUp',false)
  			Events.startEvent(Events.Room[0]);
  		},
  
  		log: function(msg){
  			console.log(msg);
  		},
  
  		getGuid: function() {
  			return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
  				var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
  				return v.toString(16);
  			});
  		},
  
  		activeModule: null,
  
  		moveTo: function(loc){
  			if(Engine.activeModule != loc){        //move to new location
  				var currentIndex = Engine.activeModule ? $('.location').index(Engine.activeModule.panel) : 1;
  				$('div.headerButton').removeClass('selected');
  				loc.tab.addClass('selected');
  
  				var slider = $('#locationSlider');
  				var panelIndex = $('.location').index(loc.panel);
  				var diff = Math.abs(panelIndex - currentIndex);
  				slider.animate({left: -(panelIndex * 700) + 'px'}, 300 * diff);
  
  				Engine.activeModule = loc;
  				loc.onArrival(diff);
  			}
  		},
  
  		event: function(cat, act) {
  			if(typeof ga === 'function') {
  				ga('send', 'event', cat, act);
  			}
  		},
  
  		moveStoresView: function(top_container, transition_diff) {
  			var stores = $('#storesContainer');
  
  			// If we don't have a storesContainer yet, leave.
  			if(typeof(stores) === 'undefined') return;
  
  			if(typeof(transition_diff) === 'undefined') transition_diff = 1;
  
  			if(top_container === null) {
  				stores.animate({top: '0px'}, {queue: false, duration: 300 * transition_diff});
  			}
  			else if(!top_container.length) {
  				stores.animate({top: '0px'}, {queue: false, duration: 300 * transition_diff});
  			}
  			else {
  				stores.animate({
  						top: top_container.height() + 26 + 'px'
  					},
  					{
  						queue: false,
  						duration: 300 * transition_diff
  				});
  			}
  		},
  
  
  		disableSelection: function() {
  			document.onselectstart = eventNullifier; // this is for IE
  			document.onmousedown = eventNullifier; // this is for the rest
  		},
  
  		enableSelection: function() {
  			document.onselectstart = eventPassthrough;
  			document.onmousedown = eventPassthrough;
  		},
  
  		updateSlider: function() {
  			var slider = $('#locationSlider');
  			slider.width((slider.children().length * 700) + 'px');
  		},
  
  		updateOuterSlider: function() {
  			var slider = $('#outerSlider');
  			slider.width((slider.children().length * 700) + 'px');
  		},
  
  		getIncomeMsg: function(num, delay) {
  			return _("{0} per {1}s", (num > 0 ? "+" : "") + num, delay);
  			//return (num > 0 ? "+" : "") + num + " per " + delay + "s";
  		},
  
  		keyLock: false,
  		tabNavigation: true,
  		restoreNavigation: false,
  
  		keyDown: function(e) {
  			e = e || window.event;
  			if(!Engine.keyLock) {
  				if(Engine.activeModule.keyDown) {
  					Engine.activeModule.keyDown(e);
  				}
  			}
  		},
  
  		KeyUp: function(e) {
  			if(Engine.activeModule.keyDown){
  				Engine.activeModule.keyDown(e);
  			}else{
  				switch(KeyboardInputManager.listen(e.which)){
  					case 0: //left
  					case 1: //up
  					case 2: //right
  					case 3: //down
  					default:
  						break;
  				}
  			}
  		},
  
  		autoSelect: function(selector) {
  			$(selector).focus().select();
  		},
  
  		handleStateUpdates: function(e){
  
  		},
  
  		setInterval: function(callback, interval, skipDouble){
  			return setInterval(callback, interval);
  		},
  
  		setTimeout: function(callback, timeout, skipDouble){
  
  			if( Engine.options.doubleTime && !skipDouble ){
  				Engine.log('Double time, cutting timeout in half');
  				timeout /= 2;
  			}
  
  			return setTimeout(callback, timeout);
  
  		}
  	};
  
  	function eventNullifier(e) {
  		return $(e.target).hasClass('menuBtn');
  	}
  
  	function eventPassthrough(e) {
  		return true;
  	}
  })();
  
  function inView(dir, elem){
  
  		var scTop = $('#main').offset().top;
  		var scBot = scTop + $('#main').height();
  
  		var elTop = elem.offset().top;
  		var elBot = elTop + elem.height();
  
  		if( dir == 'up' ){
  				// STOP MOVING IF BOTTOM OF ELEMENT IS VISIBLE IN SCREEN
  				return ( elBot < scBot );
  		}else if( dir == 'down' ){
  				return ( elTop > scTop );
  		}else{
  				return ( ( elBot <= scBot ) && ( elTop >= scTop ) );
  		}
  
  }
  
  function scrollByX(elem, x){
  
  		var elTop = parseInt( elem.css('top'), 10 );
  		elem.css( 'top', ( elTop + x ) + "px" );
  
  }
  
  
  //create jQuery Callbacks() to handle object events
  $.Dispatch = function( id ) {
  	var callbacks, topic = id && Engine.topics[ id ];
  	if ( !topic ) {
  		callbacks = jQuery.Callbacks();
  		topic = {
  				publish: callbacks.fire,
  				subscribe: callbacks.add,
  				unsubscribe: callbacks.remove
  		};
  		if ( id ) {
  			Engine.topics[ id ] = topic;
  		}
  	}
  	return topic;
  };
  
  $(function() {
  	Engine.init();
  });
  