
	var myAnimations = new Array();

	//
	// Тело объекта анимации
	//
	// {

	function myAnimation( prms ) {
		
		// Входные параметры
		if (!prms)
			prms = {}
		
		// Публикация объекта
		this.id = myAnimations.length
		myAnimations[this.id] = this
		
		// Дефолтные значения
		this.transformations = []
		this.duration = prms.duration || 500;
		this.speed = prms.speed || prms.timeOut || 20;
		this.unit = prms.unit || 'px';
		this.motion = prms.motion || false
		this.running = false
		this.paused = false
		this.obj = prms.obj || false
		
		// Хендлеры функций
		this.handlers = {
			start: new Function('myAnimations['+this.id+'].start(-1)'),
			step: new Function('myAnimations['+this.id+'].step()'),
			stop: new Function('myAnimations['+this.id+'].stop()'),
			resume: new Function('myAnimations['+this.id+'].resume()')
			}
			
		// Трансформации, если заданы
		if (prms.transformations)
			for (var i=0; i<prms.transformations.length; i++)
				if (prms.transformations[i])
					this.setTransformation( prms.transformations[i] )
			
		// Внутренние события
		this.events = {
			start: [],
			beforeStart: [],
			complete: [],
			afterStep: [],
			beforeStep: [],
			beforeRender: [],
			afterRender: []
			}
		
		return this
		}
		
	myAnimation.prototype.addEventListener = function( eventName, handler, capture ) {
		if (this.events[eventName]) {
			this.events[eventName].push( handler )
			return true
			}
		return false
		}
		
	myAnimation.prototype.removeEventListener = function( eventName, handler, capture ) {
		if (this.events[eventName]) {
			for (var i=0; i<this.events[eventName].length; i++) {
				if (this.events[eventName][i] == handler) {
					this.events[eventName][i] = false
					return true
					}
				}
			}
		return false
		}

	myAnimation.prototype.runEvent = function( eventName ) {
		for (var i=0; i<this.events[eventName].length; i++)
			if (this.events[eventName][i])
				this.events[eventName][i]()
		return true
		}

	myAnimation.prototype.start = function( delay ) {
		
		// Если анимация уже запущена
		if (delay != -1 && this.isRunning() && !this.isPaused())
			return false
		
		this.runEvent( 'beforeStart' )
		this.running = true
		
		if ( !delay || delay == -1 ) {
			this.time = 0
			this.startDelay = false
			var steps = this.duration / this.speed
			for (var i=0; i<this.transformations.length; i++) {
				if (!this.transformations[i].start && this.transformations[i].start != 0)
					this.transformations[i].start = this.getIntegerStyleProperty( this.transformations[i].propery )
				this.transformations[i].step = ( this.transformations[i].end - this.transformations[i].start ) / steps
				}
			this.intervalObj = setInterval( this.handlers.step, this.speed )
			this.runEvent( 'start' )
			return true
			} else 
				this.startDelay = setTimeout( this.handlers.start, delay )

		return true
		}
		
	myAnimation.prototype.clearStartDelay = function() { 
		if (this.startDelay) {
			clearTimeout( this.startDelay ) 
			this.startDelay = false
			this.running = false
			return true
			}
		return false
		}
		
	myAnimation.prototype.pause = function( delay ) { return this.stop( delay ) }
	myAnimation.prototype.stop = function( delay ) {
		if (this.isRunning()) {
			if (delay)
				setTimeout( this.handlers.stop, delay )
				else {
					this.paused = true
					clearInterval( this.intervalObj )
					return true
					}
			} else
				return false
		}
		
	myAnimation.prototype.resume = function( delay ) {
		if (this.isRunning()) {
			if (delay)
				setTimeout( this.handlers.resume, delay )
				else {
					this.intervalObj = setInterval( this.handlers.step, this.speed )
					this.paused = false
					return true
					}
			} else
				return false
		}
		
	myAnimation.prototype.reset = function() {
		this.paused = false
		this.running = false
		}
			
	myAnimation.prototype.step = function() {
		if (this.time >= this.duration) {
			this.time = this.duration
			this.stop()
			this.paused = false
			this.running = false
			this.runEvent( 'complete' )
			} else {
				this.runEvent( 'beforeStep' )
				this.render()
				this.time += this.speed
				this.runEvent( 'afterStep' )
				}
		return true
		}

	myAnimation.prototype.render = function() {
		this.runEvent( 'beforeRender' )
		for (var i=0; i<this.transformations.length; i++)
			this.setIntegerStyleProperty( 
				this.transformations[i].property, 
				Math[ this.transformations[i].motion || this.motion ]( 
					this.time, 
					this.transformations[i].start, 
					this.transformations[i].end - this.transformations[i].start, 
					this.duration
					)
				)
		this.runEvent( 'afterRender' )
		}
		
	myAnimation.prototype.getIntegerStyleProperty = function( stylePropertyName ) { return parseInt( this.obj.style[ stylePropertyName ] ) }
	myAnimation.prototype.setIntegerStyleProperty = function( stylePropertyName, value ) { this.obj.style[ stylePropertyName ] = Math.round( value ) + this.unit }
	myAnimation.prototype.setDuration = function( t ) { this.duration = t }
	myAnimation.prototype.setTimeout = function( timeOut ) { this.setSpeed( timeOut ) }
	myAnimation.prototype.setSpeed = function( speed ) { this.speed = speed }
	myAnimation.prototype.setUnit = function( u ) { this.unit = u }
	myAnimation.prototype.setTransformation = function( tranformationObj ) { return this.transformations.push( tranformationObj ) }
	myAnimation.prototype.isRunning = function() { return this.running }
	myAnimation.prototype.isPaused = function() { return this.poused }
	
	// }
	//
	// Методы анимации (расширения для объекта Math)
	//
	// {
	
	Math.linearTween = function(t, b, c, d) { return c*t/d + b }
	Math.easeInQuad = function(t, b, c, d) { return c*(t/=d)*t + b }
	Math.easeOutQuad = function(t, b, c, d) { return -c *(t/=d)*(t-2) + b }
	Math.easeInOutQuad = function (t, b, c, d) { return ((t/=d/2) < 1) ? c/2*t*t + b : -c/2 * ((--t)*(t-2) - 1) + b }
	Math.easeInCubic = function (t, b, c, d) { return c*(t/=d)*t*t + b }
	Math.easeOutCubic = function (t, b, c, d) { return c*((t=t/d-1)*t*t + 1) + b }
	Math.easeInOutCubic = function (t, b, c, d) { return ((t/=d/2) < 1) ? c/2*t*t*t + b : c/2*((t-=2)*t*t + 2) + b }
	Math.easeInQuart = function (t, b, c, d) { return c*(t/=d)*t*t*t + b }
	Math.easeOutQuart = function (t, b, c, d) { return -c * ((t=t/d-1)*t*t*t - 1) + b }
	Math.easeInOutQuart = function (t, b, c, d) { return ((t/=d/2) < 1) ? c/2*t*t*t*t + b : -c/2 * ((t-=2)*t*t*t - 2) + b }
	Math.easeInQuint = function (t, b, c, d) { return c*(t/=d)*t*t*t*t + b }
	Math.easeOutQuint = function (t, b, c, d) { return c*((t=t/d-1)*t*t*t*t + 1) + b }
	Math.easeInOutQuint = function (t, b, c, d) { return ((t/=d/2) < 1) ? c/2*t*t*t*t*t + b : c/2*((t-=2)*t*t*t*t + 2) + b }
	Math.easeInSine = function (t, b, c, d) { return -c * Math.cos(t/d * (Math.PI/2)) + c + b }
	Math.easeOutSine = function (t, b, c, d) { return c * Math.sin(t/d * (Math.PI/2)) + b }
	Math.easeInOutSine = function (t, b, c, d) { return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b }
	Math.easeInExpo = function (t, b, c, d) { return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b }
	Math.easeOutExpo = function (t, b, c, d) { return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b }
	Math.easeInCirc = function (t, b, c, d) { return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b }
	Math.easeOutCirc = function (t, b, c, d) { return c * Math.sqrt(1 - (t=t/d-1)*t) + b }
	Math.easeInOutCirc = function (t, b, c, d) { return ((t/=d/2) < 1) ? -c/2 * (Math.sqrt(1 - t*t) - 1) + b : c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b }
	Math.easeInBounce = function (t, b, c, d) { return c - Math.easeOutBounce (d-t, 0, c, d) + b }
	
	Math.easeInOutExpo = function (t, b, c, d) { 
		if (t==0) return b
		if (t==d) return b+c
		if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b
		return c/2 * (-Math.pow(2, -10 * --t) + 2) + b
		}

	Math.easeInElastic = function (t, b, c, d, a, p) {
		if (t==0) return b
		if ((t/=d)==1) return b+c
		if (!p) p=d*.3
		if (a < Math.abs(c)) {
			var s = p/4
			a = c
			} else 
				var s = p/(2*Math.PI) * Math.asin (c/a)
		return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b
		}

	Math.easeOutElastic = function (t, b, c, d, a, p) {
		if (t==0) 
			return b
		if ((t/=d)==1) 
			return b + c
		if (!p) p = d*.3
		if (a < Math.abs(c)) { 
			var s = p/4
			a = c
			} else 
				var s = p/(2*Math.PI) * Math.asin (c/a)
		return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b
		}

	Math.easeInOutElastic = function (t, b, c, d, a, p) {
		if (t==0) 
			return b
		if ((t/=d/2)==2) 
			return b + c
		if (!p) p = d*(.3*1.5)
		if (a < Math.abs(c)) { 
			a = c
			var s = p/4
			} else 
				var s = p/(2*Math.PI) * Math.asin (c/a);
		if (t < 1) 
			return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b
			else
			return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b
		}

	Math.easeInBack = function (t, b, c, d, s) {
		if (s == undefined) 
			s = 1.70158
		return c*(t/=d)*t*((s+1)*t - s) + b
		}

	Math.easeOutBack = function (t, b, c, d, s) {
		if (s == undefined) 
			s = 1.70158
		return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b
		}

	Math.easeInOutBack = function (t, b, c, d, s) {
		if (s == undefined) 
			s = 1.70158; 
		if ((t/=d/2) < 1) 
			return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b
			else
			return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b
		}

	Math.easeOutBounce = function (t, b, c, d) {
		if ((t/=d) < (1/2.75))
			return c*(7.5625*t*t) + b
			else if (t < (2/2.75))
			return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b
			else if (t < (2.5/2.75))
			return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b
			else
			return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b
		}

	Math.easeInOutBounce = function (t, b, c, d) {
		if (t < d/2) 
			return Math.easeInBounce (t*2, 0, c, d) * .5 + b
			else
			return Math.easeOutBounce (t*2-d, 0, c, d) * .5 + c*.5 + b
		}

	// }
