text: 
  // -----------------------------------------------------------------------------
  // Impact Game Engine 1.24
  // http://impactjs.com/
  // -----------------------------------------------------------------------------
  
  
  (function(window){ "use strict";
  
  // -----------------------------------------------------------------------------
  // Native Object extensions
  
  Number.prototype.map = function(istart, istop, ostart, ostop) {
  	return ostart + (ostop - ostart) * ((this - istart) / (istop - istart));
  };
  
  Number.prototype.limit = function(min, max) {
  	return Math.min(max, Math.max(min, this));
  };
  
  Number.prototype.round = function(precision) {
  	precision = Math.pow(10, precision || 0);
  	return Math.round(this * precision) / precision;
  };
  
  Number.prototype.floor = function() {
  	return Math.floor(this);
  };
  
  Number.prototype.ceil = function() {
  	return Math.ceil(this);
  };
  
  Number.prototype.toInt = function() {
  	return (this | 0);
  };
  
  Number.prototype.toRad = function() {
  	return (this / 180) * Math.PI;
  };
  
  Number.prototype.toDeg = function() {
  	return (this * 180) / Math.PI;
  };
  
  Object.defineProperty(Array.prototype, 'erase', {value: function(item) {
  	for( var i = this.length; i--; ) {
  		if( this[i] === item ) {
  			this.splice(i, 1);
  		}
  	}
  	return this;
  }});
  
  Object.defineProperty(Array.prototype, 'random', {value: function(item) {
  	return this[ Math.floor(Math.random() * this.length) ];
  }});
  
  Function.prototype.bind = Function.prototype.bind || function (oThis) {
  	if( typeof this !== "function" ) {
  		throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
  	}
  
  	var aArgs = Array.prototype.slice.call(arguments, 1),
  		fToBind = this,
  		fNOP = function () {},
  		fBound = function () {
  			return fToBind.apply(
  				(this instanceof fNOP && oThis ? this : oThis),
  				aArgs.concat(Array.prototype.slice.call(arguments))
  			);
  		};
  
  	fNOP.prototype = this.prototype;
  	fBound.prototype = new fNOP();
  
  	return fBound;
  };
  
  
  // -----------------------------------------------------------------------------
  // ig Namespace
  
  window.ig = {
  	game: null,
  	debug: null,
  	version: '1.24',
  	global: window,
  	modules: {},
  	resources: [],
  	ready: false,
  	baked: false,
  	nocache: '',
  	ua: {},
  	prefix: (window.ImpactPrefix || ''),
  	lib: 'lib/',
  	
  	_current: null,
  	_loadQueue: [],
  	_waitForOnload: 0,
  	
  	
  	$: function( selector ) {
  		return selector.charAt(0) == '#'
  			? document.getElementById( selector.substr(1) )
  			: document.getElementsByTagName( selector );
  	},
  	
  	
  	$new: function( name ) {
  		return document.createElement( name );
  	},
  	
  	
  	copy: function( object ) {
  		if(
  		   !object || typeof(object) != 'object' ||
  		   object instanceof HTMLElement ||
  		   object instanceof ig.Class
  		) {
  			return object;
  		}
  		else if( object instanceof Array ) {
  			var c = [];
  			for( var i = 0, l = object.length; i < l; i++) {
  				c[i] = ig.copy(object[i]);
  			}
  			return c;
  		}
  		else {
  			var c = {};
  			for( var i in object ) {
  				c[i] = ig.copy(object[i]);
  			}
  			return c;
  		}
  	},
  	
  	
  	merge: function( original, extended ) {
  		for( var key in extended ) {
  			var ext = extended[key];
  			if(
  				typeof(ext) != 'object' ||
  				ext instanceof HTMLElement ||
  				ext instanceof ig.Class ||
  				ext === null
  			) {
  				original[key] = ext;
  			}
  			else {
  				if( !original[key] || typeof(original[key]) != 'object' ) {
  					original[key] = (ext instanceof Array) ? [] : {};
  				}
  				ig.merge( original[key], ext );
  			}
  		}
  		return original;
  	},
  	
  	
  	ksort: function( obj ) {
  		if( !obj || typeof(obj) != 'object' ) {
  			return [];
  		}
  		
  		var keys = [], values = [];
  		for( var i in obj ) {
  			keys.push(i);
  		}
  		
  		keys.sort();
  		for( var i = 0; i < keys.length; i++ ) {
  			values.push( obj[keys[i]] );
  		}
  		
  		return values;
  	},
  
  	// Ah, yes. I love vendor prefixes. So much fun!
  	setVendorAttribute: function( el, attr, val ) {
  		var uc = attr.charAt(0).toUpperCase() + attr.substr(1);
  		el[attr] = el['ms'+uc] = el['moz'+uc] = el['webkit'+uc] = el['o'+uc] = val;
  	},
  
  
  	getVendorAttribute: function( el, attr ) {
  		var uc = attr.charAt(0).toUpperCase() + attr.substr(1);
  		return el[attr] || el['ms'+uc] || el['moz'+uc] || el['webkit'+uc] || el['o'+uc];
  	},
  
  
  	normalizeVendorAttribute: function( el, attr ) {
  		var prefixedVal = ig.getVendorAttribute( el, attr );
  		if( !el[attr] && prefixedVal ) {
  			el[attr] = prefixedVal;
  		}
  	},
  
  
  	// This function normalizes getImageData to extract the real, actual
  	// pixels from an image. The naive method recently failed on retina
  	// devices with a backgingStoreRatio != 1
  	getImagePixels: function( image, x, y, width, height ) {
  		var canvas = ig.$new('canvas');
  		canvas.width = image.width;
  		canvas.height = image.height;
  		var ctx = canvas.getContext('2d');
  		
  		// Try to draw pixels as accurately as possible
  		ig.System.SCALE.CRISP(canvas, ctx);
  
  		var ratio = ig.getVendorAttribute( ctx, 'backingStorePixelRatio' ) || 1;
  		ig.normalizeVendorAttribute( ctx, 'getImageDataHD' );
  
  		var realWidth = image.width / ratio,
  			realHeight = image.height / ratio;
  
  		canvas.width = Math.ceil( realWidth );
  		canvas.height = Math.ceil( realHeight );
  
  		ctx.drawImage( image, 0, 0, realWidth, realHeight );
  		
  		return (ratio === 1)
  			? ctx.getImageData( x, y, width, height )
  			: ctx.getImageDataHD( x, y, width, height );
  	},
  
  	
  	module: function( name ) {
  		if( ig._current ) {
  			throw( "Module '"+ig._current.name+"' defines nothing" );
  		}
  		if( ig.modules[name] && ig.modules[name].body ) {
  			throw( "Module '"+name+"' is already defined" );
  		}
  		
  		ig._current = {name: name, requires: [], loaded: false, body: null};
  		ig.modules[name] = ig._current;
  		ig._loadQueue.push(ig._current);
  		return ig;
  	},
  	
  	
  	requires: function() {
  		ig._current.requires = Array.prototype.slice.call(arguments);
  		return ig;
  	},
  	
  	
  	defines: function( body ) {
  		ig._current.body = body;
  		ig._current = null;
  		ig._initDOMReady();
  	},
  	
  	
  	addResource: function( resource ) {
  		ig.resources.push( resource );
  	},
  	
  	
  	setNocache: function( set ) {
  		ig.nocache = set
  			? '?' + Date.now()
  			: '';
  	},
  	
  	
  	// Stubs for ig.Debug
  	log: function() {},
  	assert: function( condition, msg ) {},
  	show: function( name, number ) {},
  	mark: function( msg, color ) {},
  	
  	
  	_loadScript: function( name, requiredFrom ) {
  		ig.modules[name] = {name: name, requires:[], loaded: false, body: null};
  		ig._waitForOnload++;
  		
  		var path = ig.prefix + ig.lib + name.replace(/\./g, '/') + '.js' + ig.nocache;
  		var script = ig.$new('script');
  		script.type = 'text/javascript';
  		script.src = path;
  		script.onload = function() {
  			ig._waitForOnload--;
  			ig._execModules();
  		};
  		script.onerror = function() {
  			throw(
  				'Failed to load module '+name+' at ' + path + ' ' +
  				'required from ' + requiredFrom
  			);
  		};
  		ig.$('head')[0].appendChild(script);
  	},
  
  	
  	_execModules: function() {
  		var modulesLoaded = false;
  		for( var i = 0; i < ig._loadQueue.length; i++ ) {
  			var m = ig._loadQueue[i];
  			var dependenciesLoaded = true;
  			
  			for( var j = 0; j < m.requires.length; j++ ) {
  				var name = m.requires[j];
  				if( !ig.modules[name] ) {
  					dependenciesLoaded = false;
  					ig._loadScript( name, m.name );
  				}
  				else if( !ig.modules[name].loaded ) {
  					dependenciesLoaded = false;
  				}
  			}
  			
  			if( dependenciesLoaded && m.body ) {
  				ig._loadQueue.splice(i, 1);
  				m.loaded = true;
  				m.body();
  				modulesLoaded = true;
  				i--;
  			}
  		}
  		
  		if( modulesLoaded ) {
  			ig._execModules();
  		}
  		
  		// No modules executed, no more files to load but loadQueue not empty?
  		// Must be some unresolved dependencies!
  		else if( !ig.baked && ig._waitForOnload == 0 && ig._loadQueue.length != 0 ) {
  			var unresolved = [];
  			for( var i = 0; i < ig._loadQueue.length; i++ ) {
  				
  				// Which dependencies aren't loaded?
  				var unloaded = [];
  				var requires = ig._loadQueue[i].requires;
  				for( var j = 0; j < requires.length; j++ ) {
  					var m = ig.modules[ requires[j] ];
  					if( !m || !m.loaded ) {
  						unloaded.push( requires[j] );
  					}
  				}
  				unresolved.push( ig._loadQueue[i].name + ' (requires: ' + unloaded.join(', ') + ')');
  			}
  			
  			throw( 
  				"Unresolved (or circular?) dependencies. " +
  				"Most likely there's a name/path mismatch for one of the listed modules " +
  				"or a previous syntax error prevents a module from loading:\n" +
  				unresolved.join('\n')				
  			);
  		}
  	},
  	
  	
  	_DOMReady: function() {
  		if( !ig.modules['dom.ready'].loaded ) {
  			if ( !document.body ) {
  				return setTimeout( ig._DOMReady, 13 );
  			}
  			ig.modules['dom.ready'].loaded = true;
  			ig._waitForOnload--;
  			ig._execModules();
  		}
  		return 0;
  	},
  	
  	
  	_boot: function() {
  		if( document.location.href.match(/\?nocache/) ) {
  			ig.setNocache( true );
  		}
  		
  		// Probe user agent string
  		ig.ua.pixelRatio = window.devicePixelRatio || 1;
  		ig.ua.viewport = {
  			width: window.innerWidth,
  			height: window.innerHeight
  		};
  		ig.ua.screen = {
  			width: window.screen.availWidth * ig.ua.pixelRatio,
  			height: window.screen.availHeight * ig.ua.pixelRatio
  		};
  		
  		ig.ua.iPhone = /iPhone/i.test(navigator.userAgent);
  		ig.ua.iPhone4 = (ig.ua.iPhone && ig.ua.pixelRatio == 2);
  		ig.ua.iPad = /iPad/i.test(navigator.userAgent);
  		ig.ua.android = /android/i.test(navigator.userAgent);
  		ig.ua.winPhone = /Windows Phone/i.test(navigator.userAgent);
  		ig.ua.iOS = ig.ua.iPhone || ig.ua.iPad;
  		ig.ua.mobile = ig.ua.iOS || ig.ua.android || ig.ua.winPhone || /mobile/i.test(navigator.userAgent);
  		ig.ua.touchDevice = (('ontouchstart' in window) || (window.navigator.msMaxTouchPoints));
  	},
  	
  	
  	_initDOMReady: function() {
  		if( ig.modules['dom.ready'] ) {
  			ig._execModules();
  			return;
  		}
  		
  		ig._boot();
  		
  		
  		ig.modules['dom.ready'] = { requires: [], loaded: false, body: null };
  		ig._waitForOnload++;
  		if ( document.readyState === 'complete' ) {
  			ig._DOMReady();
  		}
  		else {
  			document.addEventListener( 'DOMContentLoaded', ig._DOMReady, false );
  			window.addEventListener( 'load', ig._DOMReady, false );
  		}
  	}
  };
  
  
  // -----------------------------------------------------------------------------
  // Provide ig.setAnimation and ig.clearAnimation as a compatible way to use
  // requestAnimationFrame if available or setInterval otherwise
  
  // Use requestAnimationFrame if available
  ig.normalizeVendorAttribute( window, 'requestAnimationFrame' );
  if( window.requestAnimationFrame ) {
  	var next = 1,
  		anims = {};
  
  	window.ig.setAnimation = function( callback, element ) {
  		var current = next++;
  		anims[current] = true;
  
  		var animate = function() {
  			if( !anims[current] ) { return; } // deleted?
  			window.requestAnimationFrame( animate, element );
  			callback();
  		};
  		window.requestAnimationFrame( animate, element );
  		return current;
  	};
  
  	window.ig.clearAnimation = function( id ) {
  		delete anims[id];
  	};
  }
  
  // [set/clear]Interval fallback
  else {
  	window.ig.setAnimation = function( callback, element ) {
  		return window.setInterval( callback, 1000/60 );
  	};
  	window.ig.clearAnimation = function( id ) {
  		window.clearInterval( id );
  	};
  }
  
  
  // -----------------------------------------------------------------------------
  // Class object based on John Resigs code; inspired by base2 and Prototype
  // http://ejohn.org/blog/simple-javascript-inheritance/
  
  var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\bparent\b/ : /.*/;
  var lastClassId = 0;
  
  window.ig.Class = function(){};
  var inject = function(prop) {	
  	var proto = this.prototype;
  	var parent = {};
  	for( var name in prop ) {		
  		if( 
  			typeof(prop[name]) == "function" &&
  			typeof(proto[name]) == "function" && 
  			fnTest.test(prop[name])
  		) {
  			parent[name] = proto[name]; // save original function
  			proto[name] = (function(name, fn){
  				return function() {
  					var tmp = this.parent;
  					this.parent = parent[name];
  					var ret = fn.apply(this, arguments);			 
  					this.parent = tmp;
  					return ret;
  				};
  			})( name, prop[name] );
  		}
  		else {
  			proto[name] = prop[name];
  		}
  	}
  };
  
  window.ig.Class.extend = function(prop) {
  	var parent = this.prototype;
   
  	initializing = true;
  	var prototype = new this();
  	initializing = false;
   
  	for( var name in prop ) {
  		if( 
  			typeof(prop[name]) == "function" &&
  			typeof(parent[name]) == "function" && 
  			fnTest.test(prop[name])
  		) {
  			prototype[name] = (function(name, fn){
  				return function() {
  					var tmp = this.parent;
  					this.parent = parent[name];
  					var ret = fn.apply(this, arguments);			 
  					this.parent = tmp;
  					return ret;
  				};
  			})( name, prop[name] );
  		}
  		else {
  			prototype[name] = prop[name];
  		}
  	}
   
  	function Class() {
  		if( !initializing ) {
  			
  			// If this class has a staticInstantiate method, invoke it
  			// and check if we got something back. If not, the normal
  			// constructor (init) is called.
  			if( this.staticInstantiate ) {
  				var obj = this.staticInstantiate.apply(this, arguments);
  				if( obj ) {
  					return obj;
  				}
  			}
  			for( var p in this ) {
  				if( typeof(this[p]) == 'object' ) {
  					this[p] = ig.copy(this[p]); // deep copy!
  				}
  			}
  			if( this.init ) {
  				this.init.apply(this, arguments);
  			}
  		}
  		return this;
  	}
  	
  	Class.prototype = prototype;
  	Class.prototype.constructor = Class;
  	Class.extend = window.ig.Class.extend;
  	Class.inject = inject;
  	Class.classId = prototype.classId = ++lastClassId;
  	
  	return Class;
  };
  
  // Merge the ImpactMixin - if present - into the 'ig' namespace. This gives other
  // code the chance to modify 'ig' before it's doing any work.
  if( window.ImpactMixin ) {
  	ig.merge(ig, window.ImpactMixin);
  }
  
  })(window);
  
  
  
  // -----------------------------------------------------------------------------
  // The main() function creates the system, input, sound and game objects,
  // creates a preloader and starts the run loop
  
  ig.module(
  	'impact.impact'
  )
  .requires(
  	'dom.ready',
  	'impact.loader',
  	'impact.system',
  	'impact.input',
  	'impact.sound'
  )
  .defines(function(){ "use strict";
  
  ig.main = function( canvasId, gameClass, fps, width, height, scale, loaderClass ) {
  	ig.system = new ig.System( canvasId, fps, width, height, scale || 1 );
  	ig.input = new ig.Input();
  	ig.soundManager = new ig.SoundManager();
  	ig.music = new ig.Music();
  	ig.ready = true;
  	
  	var loader = new (loaderClass || ig.Loader)( gameClass, ig.resources );
  	loader.load();
  };
  
  });
  