// base objects extensions
// this code is heavily minified and it couldn not be changed frequently
;(function(){

var O = Object, A = Array, Ap = A.prototype, S = String, Sp = S.prototype, Fp = Function.prototype, D = Date, M = Math

function add (d, s) { if (d) for (var k in s) if (!(k in d)) d[k] = s[k]; return d }
function extend (d, s) { if (d) for (var k in s) d[k] = s[k]; return d }

add
(
	O,
	{
		add: add,
		extend: extend,
		copy: function (s) { var d = {}; for (var k in s) d[k] = s[k]; return d },
		keys: function (s) { var r = []; for (var k in s) r.push(k); return r },
		keysCount: function (s) { var l = 0; for (var k in s) l++; return l },
		values: function (s) { var r = []; for (var k in s) r.push(s[k]); return r },
		isEmpty: function (s) { for (var k in s) return false; return true }
	}
)

add
(
	S,
	{
		localeCompare: function (a, b) { return a < b ? -1 : (a > b ? 1 : 0) }
	}
)

add
(
	Sp,
	{
		trim: function () { return this.replace(/^\s+|\s+$/g, '') },
		capitalize: function () { return this.charAt(0).toUpperCase() + this.substr(1) }
	}
)

add
(
	Fp,
	{
		mixIn: function (module) { return extend(this.prototype, module.prototype) },
		extend: function (s) { for (var k in s) this[k] = s[k]; return this },
		bind: function (inv, args) { var me = this; return function () { me.apply(inv, args || arguments) } }
	}
)

var ceil = M.ceil, floor = M.floor, round = M.round, random = M.random
add(M, {longRandom: function () { return (new D()).getTime().toString() + round(random() * 1E+17) }})


add
(
	Ap,
	{
		indexOf: function (v, i)
		{
			var len = this.length
			
			if ((i = +i))
			{
				if (i < 0)
					i = ceil(i) + len
				else
					i = floor(i)
			}
			else
				i = 0
			
			for (; i < len; i++)
				if (i in this && this[i] === v)
					return i
			return -1
		},
		uniq: function ()
		{
			var res = [], j = 0
			for (var i = 0, il = this.length; i < il; i++)
			{
				var v = this[i]
				if (res.indexOf(v) === -1)
					res[j++] = v
			}
			return res
		},
		forEach: function (f, inv) { for (var i = 0, len = this.length; i < len; i++) f.call(inv, this[i], i, this) },
		map: function(f, inv)
		{
			var len = this.length,
				res = new A(len)
			for (var i = 0; i < len; i++)
				if (i in this)
					res[i] = f.call(inv, this[i], i, this)
			return res
		}
	}
)

add(A, {copy: function (src) { return Ap.slice.call(src) }})

})();
;(function(){

var s = self

if (!s.log)
{
	// console object present
	if (s.console)
		s.log = function () { s.console.log.apply(s.console, arguments) }
	
	// Opera
	else if (s.opera && s.opera.postError)
		s.log = function () { return s.opera.postError(arguments) }
	
	// none
	else
		s.log = function () {}
}

})();

// 1, 2, 5: банкир, банкира, банкиров
String.prototype.plural = Number.prototype.plural = function (a, b, c)
{
	if (this % 1)
		return b
	
	var v = Math.abs(this) % 100
	if (11 <= v && v <= 19)
		return c
	
	v = v % 10
	if (2 <= v && v <= 4)
		return b
	if (v == 1)
		return a
	
	return c
}

String.prototype.pluralA = Number.prototype.pluralA = function (ary)
{
	return this.plural(ary[0], ary[1], ary[2])
}

;(function(){

var random = Math.random

Array.prototype.randomize = function ()
{
	for (var i = 0, il = this.length; i < il; i++)
	{
		var j = (random() * il) >> 0
		var v = this[j]
		this[j] = this[i]
		this[i] = v
	}
	
	return this
}

Array.prototype.random = function (n)
{
	var len = this.length
	
	if (n > len)
		n = len
	
	if (n > 1)
	{
		var copy = this.slice()
		copy.randomize()
		return n === len ? copy : copy.slice(0, n)
	}
	
	if (n === 1)
		return [this[(random() * len) >> 0]]
	
	// n <= 0
	return []
}

})();
;(function(){

var myName = 'MVC'

function Me () {}

Me.prototype =
{
	__mvc_interlink: function ()
	{
		var constructor = this.constructor,
			model = this.model = new constructor.Model(),
			view = this.view = new constructor.View(),
			controller = this.controller = new constructor.Controller()
		
		model.view = controller.view = view
		view.controller = controller
		controller.model = model
		model.parent = view.parent = controller.parent = this
	},
	
	initialize: function () {}
}

self[myName] = Me
Me.className = myName

function Model () {}
Model.prototype.initialize = function () {}
Model.className = myName + '.Model'
Me.Model = Model

function View () {}
View.prototype.initialize = function () {}
View.className = myName + '.View'
Me.View = View

function Controller () {}
Controller.prototype.initialize = function () {}
Controller.className = myName + '.Controller'
Me.Controller = Controller


Me.setup = function (klass, name, parent)
{
	if (!parent)
		parent = Me
	
	klass.prototype = new parent()
	klass.className = name
	
	
	function Model ()
	{
		this.constructor = Model
		this.initialize.apply(this, arguments)
	}
	Model.className = name + '.Model'
	Model.prototype = new parent.Model()
	klass.Model = Model
	
	
	function View ()
	{
		this.constructor = View
		this.initialize.apply(this, arguments)
	}
	View.className = name + '.View'
	View.prototype = new parent.View()
	klass.View = View
	
	
	function Controller ()
	{
		this.constructor = Controller
		this.initialize.apply(this, arguments)
	}
	Controller.className = name + '.Controller'
	Controller.prototype = new parent.Controller()
	klass.Controller = Controller
	
	
	return klass
}

Me.create = function (name, parent)
{
	function klass ()
	{
		this.constructor = klass
		this.__mvc_interlink()
		this.initialize()
	}
	
	return this.setup(klass, name, parent)
}

})();

// inspired by RequireJS (http://requirejs.org/) by James Burke (http://twitter.com/jrburke)
;(function(){

var myName = 'require',
	states = {}

function run (callbacks, data)
{
	for (var i = 0, il = callbacks.length; i < il; i++)
		callbacks[i](data)
}

function Me (name, f)
{
	var src = Me.names[name] || name
	
	var state = states[src]
	
	if (state)
	{
		if (state.loaded)
			setTimeout(function () { run([f], state.data) })
		else
			state.callbacks.push(f)
	}
	else
	{
		state = states[src] = {callbacks: [f]}
		
		function onload ()
		{
			if (state.loaded)
				return
			state.loaded = true
			state.data = Me.lastData
			
			run(state.callbacks, state.data)
		}
		
		var script = state.node = Me.rootNode.appendChild(document.createElement('script'))
		script.addEventListener('load', onload, false)
		script.src = src
	}
	
	return state.node
}

Me.data = function (data)
{
	this.lastData = data
}

Me.names = {}
Me.rootNode = document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0] || document.documentElement

Me.className = myName
self[myName] = Me

})();

;(function(){

function list2array (list)
{
	var arr = []
	for (var i = 0, il = list.length; i < il; i++)
		arr[i] = list[i]
	return arr
}

window.$$ = function (query, root)
{
	var list = (root || document).querySelectorAll(query)
	// if (!list || list.length == 0)
	// 	alert('empty $$("' + query + '")')
	return list2array(list)
}
window.$ = function (id) { return document.getElementById(id) }

if (!document.getElementsByClassName)
Element.prototype.getElementsByClassName = document.getElementsByClassName = function (className)
{
	return this.querySelectorAll('.' + className)
}

})();

$.onload = function (fn) { return self.addEventListener('load', fn, false) }
$.load = function (src)
{
	var me = arguments.callee
	var cache = me.cache || (me.cache = {}) 
	if (me.cache[src])
		return me.cache[src]
	var node = document.createElement('script')
	node.type = 'text/javascript'
	node.src = src
	document.getElementsByTagName('head')[0].appendChild(node)
	cache[src] = node
	return node
}
$.iamready = function ()
{
	var e = document.createEvent('Event')
	e.initEvent('ready', false, false)
	document.dispatchEvent(e)
}
$.onready = function (fn) { return this.onready.listeners.push(fn) }
$.onready.done = 0
$.onready.listeners = []
$.onready.run = function (e)
{
	if (this.done++)
		return
	
	if (!e)
		e = {type:'contentready'}
	
	var listeners = this.listeners
	for (var i = 0; i < listeners.length; i++)
		listeners[i].call(document, e)
}
$.onload(function (e) { $.onready.run(e) })
self.addEventListener('DOMContentLoaded', function (e) { $.onready.run(e) }, false)
;(function(){

var R = RegExp, rexCache = {}

Object.add
(
	Element.prototype,
	{
		setClassName: function (cn)
		{
			this.className = cn
			return cn
		},
		
		addClassName: function (cn)
		{
			// this.removeClassName(cn)
			var className = this.className
			if (!className)
				this.className = cn
			else
				this.className = className + ' ' + cn
			return cn
		},
		
		addClassNames: function (cns)
		{
			var className = this.className
			if (!className)
				this.className = cns.join(' ')
			else
				this.className = className + ' ' + cns.join(' ')
			return cns
		},
		
		removeClassName: function (cn)
		{
			var className = this.className
			if (className)
			{
				// the following regexp has to be the exact copy of the regexp from hasClassName()
				// because these two methods have the same regexp cache
				this.className = className.replace(rexCache[cn] || (rexCache[cn] = new R('(?:^| +)(?:' + cn + '(?:$| +))+', 'g')), ' ')
										  .replace(/^\s+|\s+$/g, '') // trim
			}
			return cn
		},
		
		toggleClassName: function (cn, state)
		{
			if (arguments.length < 2)
				state = !this.hasClassName(cn)
			
			this.removeClassName(cn)
			if (state)
				this.addClassName(cn)
		},
		
		hasClassName: function (cn)
		{
			var className = this.className
			if (className == cn)
				return true
			
			// the following regexp has to be the exact copy of the regexp from removeClassName()
			// because these two methods have the same regexp cache
			var rex = rexCache[cn]
			if (rex)
				rex.lastIndex = 0
			else
				rex = rexCache[cn] = new R('(?:^| +)(?:' + cn + '(?:$| +))+', 'g')
			
			return rex.test(className)
		},
		
		empty: function ()
		{
			var node
			while (node = this.firstChild)
				this.removeChild(node)
		},
		
		hide: function () { this.addClassName('hidden') },
		show: function () { this.removeClassName('hidden') },
		
		remove: function ()
		{
			var parent = this.parentNode
			return parent ? parent.removeChild(this) : this
		},
		
		isParent: function (parent, root)
		{
			var node = this
			do
			{
				if (node === parent)
					return true
				if (node === root)
					break
			}
			while ((node = node.parentNode))
			
			return false
		},
		
		offsetPosition: function (root)
		{
			var node = this,
				left = 0, top = 0
			
			if (node == root)
				return {left: left, top: top}
			
			var parent, lastNode
			for (;;)
			{
				left += node.offsetLeft
				top += node.offsetTop
				
				parent = node.offsetParent
				if (parent && parent !== root)
				{
					lastNode = node
					node = parent
				}
				else
				{
					if (lastNode)
					{
						left -= lastNode.scrollLeft
						top -= lastNode.scrollTop
					}
					
					break
				}
			}
			
			return {left: left, top: top}
		}
	}
)

})();
;(function(){

var doc = document, undef, myName = 'NodesShortcut'

function T (text)
{
	return doc.createTextNode(text)
}

function N (tag)
{
	return doc.createElement(tag)
}

function Nc (tag, cn)
{
	var node = doc.createElement(tag)
	node.className = cn
	return node
}

function Nct (tag, cn, text)
{
	var node = doc.createElement(tag)
	node.className = cn
	node.appendChild(doc.createTextNode(text))
	return node
}


function E (tag, cn, props)
{
	var node = doc.createElement(tag)
	if (cn !== undef) node.className = cn
	if (props)
		for (var i in props)
			node.setAttribute(i, props[i])
	return node
}

var Me = self[myName] = {}
	funcs = Me.funcs = {T: T, N: N, Nc: Nc, Nct: Nct, E: E}

var pairs = []
for (var k in funcs)
	pairs.push(k + '=' + myName + '.funcs.' + k)

Me.code = 'var ' + pairs.join(',')
Me.include = function () { return this.code }


})();

;(function(){

var myName = 'EventDriven',
	Me = self[myName] = function () {},
	handlersProp = '__' + myName + 'Handlers',
	doc = document

Me.prototype =
{
	addEventListener: function (type, listener, capture)
	{
		var handlers, harr
		if (handlers = this[handlersProp])
		{
			if (harr = handlers[type])
				harr.indexOf(listener) < 0 ? harr.push(listener) : 1
			else
				handlers[type] = [listener]
		}
		else
			(this[handlersProp] = {})[type] = [listener]
	},
	
	removeEventListener: function (type, listener, capture)
	{
		var handlers, harr, i, len
		if (handlers = this[handlersProp])
			if ((harr = handlers[type]))
			{
				if ((i = harr.indexOf(listener)) >= 0)
				{
					for (len = harr.length; i < len; i++)
						harr[i] = harr[i + 1]
					harr.length--
				}
			}
	},
	
	dispatchEvent: function (e)
	{
		e.__dispatched = true
		var handlers, harr, len
		if ((handlers = this[handlersProp]))
			if ((harr = handlers[e.type]))
				if ((len = harr.length))
				{
					for (var i = 0; i < len; i++)
						harr[i].call(this, e)
					return !e.defaultPrevented
				}
		
		return true
	},
	
	dispatchEventData: function (type, data)
	{
		var e = new Event()
		e.type = type
		e.data = data
		return this.dispatchEvent(e)
	}
}

function Event () {}

Event.prototype =
{
	bubbles: true,
	cancelable: true,
	
	preventDefault: function ()
	{
		if (this.__dispatched && this.cancelable)
			this.defaultPrevented = true
	},
	
	stopPropagation: function ()
	{
		this.propagationStopped = true
	},
	
	initEvent: function (type, bubbles, cancelable)
	{
		this.type = type
		this.bubbles = bubbles
		this.cancelable = cancelable
	}
}

Me.Event = Event

})();

;(function () {

var myName = 'GlobalTimer', Me =
{
	fps: 60,
	total: 0,
	id: 0,
	timers: {},
	timer: null,
	
	tick: function (d)
	{
		var timer, timers = this.timers
		for (var id in timers)
			if ((timer = timers[id]))
				timer(d)
	},
	
	add: function (callback)
	{
		// if was no timers
		if (this.total++ <= 0)
		{
			if (this.timer !== null)
				throw new Error(myName + '.timer had been broken')
			var me = this
			this.timer = setInterval(function (d) { me.tick(d) }, 1000 / this.fps)
		}
		
		this.timers[++this.id] = callback
		return this.id
	},
	
	remove: function (id)
	{
		if (id in this.timers)
		{
			var callback = this.timers[id]
			delete this.timers[id]
			
			// if have deleted last timer
			if (--this.total <= 0)
			{
				clearInterval(this.timer)
				this.timer = null
			}
			
			return callback
		}
	},
	
	clear: function (d)
	{
		var timers = this.timers
		for (var id in timers)
			this.remove(id)
	}
}

self[myName] = Me

})();

;(function(){

function Kinematics () {}
Kinematics.className = 'Kinematics'
self[Kinematics.className] = Kinematics

var fps = Kinematics.fps = GlobalTimer.fps

function stub () {}

function Space ()
{
	this.timers = {}
	this.ticks = 0
	this.freeze = 0
	this.points = []
	this.forces = []
}

Space.prototype =
{
	minPulse: 1 / (fps * fps *10),
	maxFreeze: fps, // wait one second before freeze
	
	ontick: stub,
	ontimeout: stub,
	onfreeze: stub,
	
	run: function (timeout)
	{
		var me = this
		clearTimeout(this.timers.timeout)
		if (timeout)
			this.timers.timeout = setTimeout(function (d) { me.timeout(d) }, timeout)
		
		if (this.running)
			return
		this.running = true
		
		this.freeze = 0
		
		this.timers.tick = GlobalTimer.add(function (d) { me.tick(d) })
	},
	
	timeout: function (d)
	{
		this.ontimeout()
		this.stop()
	},
	
	stop: function ()
	{
		if (!this.running)
			return
		this.running = false
		
		clearTimeout(this.timers.timeout)
		GlobalTimer.remove(this.timers.tick)
	},
	
	tick: function (d)
	{
		this.ticks++
		
		var forces = this.forces, points = this.points
		for (var i = 0, il = forces.length; i < il; i++)
		{
			var force = forces[i]
			for (var j = 0, jl = points.length; j < jl; j++)
				force.apply(points[j])
		}
		
		this.ontick()
		
		var pulse = 0
		for (var i = 0, il = points.length; i < il; i++)
		{
			var p = points[i], v = p.v
			p.x += v.x
			p.y += v.y
		}
		
		for (var i = 0, il = points.length; i < il; i++)
		{
			var v = points[i].v
			pulse += v.x * v.x + v.y * v.y
		}
		
		if (!pulse || pulse < this.minPulse)
		{
			if (++this.freeze == this.maxFreeze)
			{
				this.freeze = 0
				if (this.onfreeze() !== false)
					this.stop()
			}
		}
		else
			this.freeze = 0
		
		this.pulse = pulse
	},
	
	add: function (object)
	{
		if (object instanceof Force)
			this.forces.push(object)
		else if (object instanceof Point)
			this.points.push(object)
		else
			throw new Error('unknown object added ' + object)
		
		return object
	}
}

Space.className = 'Space'
Kinematics[Space.className] = Space


function Point (x, y, vx, vy, m)
{
	this.x = x || 0
	this.y = y || 0
	this.m = m || 1
	this.v = new Vector(vx ? vx / fps : 0, vy ? vy / fps : 0)
}

Point.prototype =
{
	
}

Point.className = 'Point'
Kinematics[Point.className] = Point


function Force () {}

Force.prototype =
{
	apply: function () {}
}

Force.className = 'Force'
Kinematics[Force.className] = Force



function Friction (mu)
{
	this.mu = mu / fps
}

Friction.prototype = new Force()
Friction.prototype.apply = function (point)
{
	point.v.addC(-this.mu)
}

Friction.className = 'Friction'
Kinematics[Friction.className] = Friction



function Wave (step, soft, min)
{
	this.setup(step, soft, min)
}

Wave.prototype = new Force()
Wave.prototype.setup = function (step, soft, min, max)
{
	this.step = step
	this.soft = soft || 10
	this.min = min / fps || 0
	this.max = max / fps || 500
}
Wave.prototype.apply = function (point)
{
	var x = Math.round(point.x), step = this.step,
		pos = x % step,
		shift = x < 0 ? step + pos : pos,
		dir = shift > step / 2 ? shift - step : shift,
		sign = dir < 0 ? 1 : -1,
		v = Math.sqrt(Math.abs(dir)) / this.soft
	
	if (v < this.min)
		v = this.min
	else if (v > this.max)
		v = this.max
	
	if (dir)
		point.v.addX(sign * v)
}

Wave.className = 'Wave'
Kinematics[Wave.className] = Wave



function Vector (x, y)
{
	this.x = x
	this.y = y
	this.h = -1
}

Vector.prototype =
{
	set: function (x, y)
	{
		this.x = x
		this.y = y
		this.h = -1
	},
	
	addX: function (x)
	{
		this.x += x
		this.h = -1
	},
	
	add: function (x, y)
	{
		this.x += x
		this.y += y
		this.h = -1
	},
	
	addC: function (c)
	{
		var x = this.x, y = this.y
		
		var h = this.h
		if (h === -1)
			h = this.h = Math.sqrt(x * x + y * y)
		
		if (h === 0)
			return
		
		var cos = x / h,
			sin = y / h
		
		h += c
		
		if (h > 0)
		{
			this.x = h * cos
			this.y = h * sin
			this.h = h
		}
		else
		{
			this.x = 0
			this.y = 0
			this.h = 0
		}
	}
}

Vector.className = 'Vector'
self[Vector.className] = Vector


})();
;(function(){

var myName = 'Moveable'

function Me () {}

function preventDefault (e){ e.preventDefault() }
var dropClick = false
function onclick (e)
{
	if (dropClick)
	{
		e.preventDefault()
		dropClick = false
	}
}
Me.dropClick = function () { dropClick = true }

var clickListener = false
Me.bindClickListened = function ()
{
	if (clickListener)
		return
	
	document.addEventListener('click', onclick, true)
	clickListener = true
}

Me.prototype =
{
	bind: function (node)
	{
		this.node = node
		
		var me = this
		this.mousedown = function (e) { me.ondown(e) }
		this.mousemove = function (e) { me.onmove(e) }
		this.mousemove2 = function (e) { me.onmove2(e) }
		this.mouseup = function (e) { me.onup(e) }
		this.mouseup2 = function (e) { me.onup2(e) }
		
		node.addEventListener('mousedown', this.mousedown, false)
		node.addEventListener('selectstart', preventDefault, false)
		
		Me.bindClickListened()
		
		return this
	},
	
	ondown: function (e)
	{
		if (this.disabled)
			return
		
		if (this.dispatchEventData('moveabout', {event: e, mousedownEvent: this.mousedownEvent}))
		{
			this.startX = e.clientX
			this.startY = e.clientY
			this.movements = []
			this.mousedownEvent = e
			
			e.preventDefault()
			
			document.addEventListener('mousemove', this.mousemove, true)
			document.addEventListener('mouseup', this.mouseup, true)
		}
	},
	
	onmove: function (e)
	{
		var dx = e.clientX - this.startX,
			dy = e.clientY - this.startY
		
		this.movements.push({dx: dx, dy: dy})
		
		if (dx * dx > 9 || dy * dy > 9)
		{
			if (this.dispatchEventData('movestart', {event: e, mousedownEvent: this.mousedownEvent}))
			{
				Me.dropClick()
				
				if (this.softStart)
				{
					this.startX = e.clientX
					this.startY = e.clientY
				}
				
				document.removeEventListener('mousemove', this.mousemove, true)
				document.removeEventListener('mouseup', this.mouseup, true)
				
				document.addEventListener('mousemove', this.mousemove2, true)
				document.addEventListener('mouseup', this.mouseup2, true)
				
				this.onmove2(e)
			}
		}
		else
			this.dispatchEventData('movestarting', {event: e, mousedownEvent: this.mousedownEvent})
	},
	
	onup: function (e)
	{
		document.removeEventListener('mousemove', this.mousemove, true)
		document.removeEventListener('mouseup', this.mouseup, true)
		this.mousedownEvent = null
	},
	
	onmove2: function (e)
	{
		var dx = e.clientX - this.startX,
			dy = e.clientY - this.startY
		
		this.movements.push({dx: dx, dy: dy})
		
		e.preventDefault()
		e.stopPropagation()
		
		if (this.lastDX != dx || this.lastDY != dy)
		{
			this.lastDX = dx
			this.lastDY = dy
			this.dispatchEventData('move', {event: e, dx: dx, dy: dy})
		}
	},
	
	onup2: function (e)
	{
		var dx = e.clientX - this.startX,
			dy = e.clientY - this.startY
		
		if (this.dispatchEventData('moveend', {event: e, dx: dx, dy: dy, movements: this.movements}))
		{
			e.preventDefault()
			e.stopPropagation()
			
			document.removeEventListener('mousemove', this.mousemove2, true)
			document.removeEventListener('mouseup', this.mouseup2, true)
		}
		
		this.mousedownEvent = null
	}
}

Me.mixIn(EventDriven)

self[myName] = Me
Me.className = myName

})();
;(function(){

var myName = 'InfiniteScroller'

function Me ()
{
	this.nodes = {}
}

Me.prototype =
{
	power: 1.5,
	spaceTimeout: 30000,
	maxInertia: 500,
	onscroll: function () {},
	
	bind: function (root, width)
	{
		this.nodes.root = root
		this.globalX = root.scrollLeft
		
		var clientWidth = root.clientWidth
		this.setWidth(width || this.guessWidth())
		
		var moveable = this.moveable = new Moveable().bind(root)
		moveable.softStart = true
		
		var me = this
		moveable.addEventListener('moveabout', function (e) { me.onmoveabout(e) }, false)
		moveable.addEventListener('movestart', function (e) { me.onmovestart(e) }, false)
		moveable.addEventListener('move', function (e) { me.onmoving(e) }, false)
		moveable.addEventListener('moveend', function (e) { me.onmoveend(e) }, false)
		
		this.setX = function (x)
		{
			if (me.globalX == x)
				return
			me.globalX = x
			
			var w = me.width,
				real
			if (w == 0)
				real = 0
			else
				real = x < 0 ? w + x % w : x % w
			root.scrollLeft = Math.round(real)
			this.onscroll(x, real)
		}
		
		
		var space = this.space = new Kinematics.Space()
		var point = this.point = new Kinematics.Point(0, 0, 0, 0)
		space.add(point)
		
		space.ontick = function () { me.spaceTick() }
		
		return this
	},
	
	guessWidth: function ()
	{
		var root = this.nodes.root
		return root.scrollWidth - root.clientWidth
	},
	
	setWidth: function (width)
	{
		this.width = width
	},
	
	setMovable: function (v)
	{
		this.moveable.disabled = !v
	},
	
	reset: function ()
	{
		this.space.stop()
		this.setX(0)
		this.point.x = this.globalX
		this.setVelocity(0, 0)
	},
	
	spaceTick: function ()
	{
		this.setX(this.point.x)
	},
	
	onmovestart: function (e)
	{
		this.space.stop()
		this.startX = this.globalX
		this.nodes.root.addClassName('grabbing')
	},
	
	onmoveabout: function ()
	{
		if (this.space.running)
		{
			Moveable.dropClick()
			this.space.stop()
		}
	},
	
	onmoving: function (e)
	{
		this.setX(this.startX - e.data.dx)
	},
	
	onmoveend: function (e)
	{
		this.nodes.root.removeClassName('grabbing')
		
		var ms = e.data.movements.reverse()
		if (!ms[3])
			return
		
		var root = this.nodes.root,
			// approximating last movements
			vx = ((ms[1].dx - ms[0].dx) + (ms[2].dx - ms[1].dx) + (ms[3].dx - ms[2].dx)) / 3// + (ms[4].dx - ms[3].dx) + (ms[5].dx - ms[4].dx)) / 5
		
		if (Math.abs(vx) > this.maxInertia)
			vx = (vx < 0 ? -1 : 1) * this.maxInertia
		
		this.point.x = this.globalX
		this.setVelocity(vx ? vx * this.power : 0, 0)
		this.run()
	},
	
	addVelocity: function (x, y)
	{
		this.point.v.add(x, y)
	},
	
	setVelocity: function (x, y)
	{
		this.point.v.set(x, y)
	},
	
	run: function (timeout)
	{
		this.space.run(timeout === undefined ? this.spaceTimeout : timeout) // set a reasonable timeout
	}
}

Me.className = myName
self[myName] = Me

})();
;(function(){

var myName = 'Gridder'

function Me (boxes, x, y)
{
	this.boxes = []
	this.gridH = {}
	this.gridA = []
	this.constructor = Me
	
	if (boxes)
		this.setBoxes(boxes)
	
	if (x && y)
		this.setStep(x, y)
}

Me.prototype =
{
	stepX: 500, stepY: 500,
	maxSteps: 5000,
	
	reflow: function ()
	{
		var boxes = this.boxes, gridH = this.gridH = {}, gridA = this.gridA = [],
			sx = this.stepX, sy = this.stepY,
			stepsLeft = this.maxSteps
		
		var ceil = Math.ceil
		
		for (var i = 0, il = boxes.length; i < il; i++)
		{
			var box = boxes[i]
			
			// mark box with an integer ID
			// simplifying future operations of search
			box.boxID = i
			
			// x and width
			var x1, x2, x = box.x, w = box.w
			x1 = x < 0 ? -ceil(-x / sx) : x / sx >> 0
			if (w <= 0)
				x2 = x1
			else
			{
				x += w
				x2 = x > 0 ? ceil(x / sx) - 1 : (x / sx >> 0) - 1
			}
			
			// y and height
			var y1, y2, y = box.y, h = box.h
			y1 = y < 0 ? -ceil(-y / sy) : y / sy >> 0
			if (h <= 0)
				y2 = y1
			else
			{
				y += h
				y2 = y > 0 ? ceil(y / sy) - 1 : (y / sy >> 0) - 1
			}
			
			for (var x = x1; x <= x2; x++)
			for (var y = y1; y <= y2; y++)
			{
				if (0 == stepsLeft--)
					throw new Me.Error('too many steps (' + this.maxSteps + ')')
				
				// check diapason of the values
				if (x >> 15 || y >> 15)
				{
					// unsafe, so using slow string key on gridH
					var key = x + ':' + y
					
					var cell = gridH[key]
					if (cell)
						cell.push(box)
					else
						gridH[key] = [box]
					
				}
				else
				{
					// safe, so using fast integer key on gridA
					var key = (x << 15) + y
					
					var cell = gridA[key]
					if (cell)
						cell.push(box)
					else
						gridA[key] = [box]
				}
			}
		}
	},
	
	// as far as JavaScript has no macros system or semi-reliable function inlining
	// you can see a heavy copy-paste here, it's for performance purpose only
	getCells: function (x, y, w, h)
	{
		var gridH = this.gridH, gridA = this.gridA,
			sx = this.stepX, sy = this.stepY,
			stepsLeft = this.maxSteps
		
		var ceil = Math.ceil
		
		// x and width
		var x1 = x < 0 ? -ceil(-x / sx) : x / sx >> 0
		if (w <= 0)
			var x2 = x1
		else
		{
			x += w
			var x2 = x > 0 ? ceil(x / sx) - 1 : (x / sx >> 0) - 1
		}
			
		// y and height
		var y1 = y < 0 ? -ceil(-y / sy) : y / sy >> 0
		if (h <= 0)
			var y2 = y1
		else
		{
			y += h
			var y2 = y > 0 ? ceil(y / sy) - 1 : (y / sy >> 0) - 1
		}
		
		var cells = []
		for (var x = x1; x <= x2; x++)
		for (var y = y1; y <= y2; y++)
		{
			if (0 == stepsLeft--)
				throw new Me.Error('too many steps (' + this.maxSteps + ')')
			
			// check diapason of the values
			if (x >> 15 || y >> 15)
			{
				// unsafe, so using slow string key on gridH
				var key = x + ':' + y
				
				var cell = gridH[key]
				if (cell)
					cells.push(cell)
			}
			else
			{
				// safe, so using fast integer key on gridA
				var key = (x << 15) + y
				
				var cell = gridA[key]
				if (cell)
					cells.push(cell)
			}
		}
		
		return cells
	},
	
	getBoxes: function (x, y, w, h)
	{
		var cells = this.getCells(x, y, w, h),
			seen = [], boxes = [], k = 0
		
		for (var i = 0, il = cells.length; i < il; i++)
		{
			var cell = cells[i]
			for (var j = 0; j < cell.length; j++)
			{
				var box = cell[j], id = box.boxID
				if (!seen[id])
				{
					seen[id] = true
					boxes[k++] = box
				}
			}
		}
		
		return boxes
	},
	
	getBoxesPrecise: function (x, y, w, h)
	{
		var boxes = this.getBoxes(x, y, w, h),
			res = []
		
		var ax1 = x, ax2 = ax1 + w, ay1 = y, ay2 = ay1 + h
		for (var i = 0, j = 0, il = boxes.length; i < il; i++)
		{
			var box = boxes[i]
			
			var bx1 = box.x, bx2 = bx1 + box.w, by1 = box.y, by2 = by1 + box.h
			
			// checking x
			if (ax2 <= bx1 || bx2 <= ax1)
				continue
			
			// checking y
			if (ay2 <= by1 || by2 <= ay1)
				continue
			
			res[j++] = box
		}
		
		return res
	},
	
	setStep: function (x, y)
	{
		this.stepX = x
		this.stepY = y
		this.reflow()
	},
	
	setBoxes: function (boxes)
	{
		this.boxes = boxes
		this.reflow()
	},
	
	getCell: function (x, y)
	{
		return x >> 15 || y >> 15 ? this.gridH[x + ':' + y] : this.gridA[(x << 15) + y]
	}
}

Me.Error = function (m) { this.name = myName + '.Error'; this.message = m }
Me.Error.prototype = new Error()

Me.className = myName
self[myName] = Me

})();
;(function(){

var myName = 'VisibilityFrame'

function Me ()
{
	this.x = 0
	this.y = 0
	this.gridder = new Gridder()
	this.boxes = []
	this.visible = {}
	this.constructor = Me
}

Me.prototype =
{
	onmove: function (show, hide, visible) {},
	
	setBoxes: function (boxes)
	{
		this.boxes = boxes
		this.visible = {}
		
		this.gridder.setBoxes(boxes)
		this.update()
	},
	
	setFrame: function (w, h, x, y)
	{
		this.width = w
		this.height = h
		
		if (x && y)
			this.setStep(x, y)
	},
	
	setStep: function (x, y)
	{
		this.gridder.setStep(x, y)
	},
	
	// much faster version
	moveTo: function (x, y)
	{
		this.x = x
		this.y = y
		
		var last = this.visible, current = {}, show = [], hide = []
		
		var boxes = this.gridder.getBoxesPrecise(x, y, this.width, this.height)
		for (var i = 0, il = boxes.length; i < il; i++)
		{
			var box = boxes[i],
				id = box.boxID
			
			if (id in last)
				delete last[id]
			else
				show.push(box)
			
			current[id] = box
		}
		
		for (var k in last)
			hide.push(last[k])
		
		this.visible = current
		
		this.onmove(show, hide, boxes)
	},
	
	update: function ()
	{
		this.moveTo(this.x, this.y)
	}
	
	// // slow version
	// moveTo: function (x, y)
	// {
	// 	var boxes = this.gridder.getBoxesPrecise(x, y, this.width, this.height)
	// 	
	// 	var visible = this.visible
	// 	this.visible = boxes
	// 	
	// 	this.onmove(boxes, visible, boxes)
	// }
}

Me.className = myName
self[myName] = Me

})();
;(function(){

var myName = 'Boxer'

var Me =
{
	nodesToBoxes: function (nodes, root, width, height)
	{
		var boxes = []
		
		var custom = width !== undefined && height !== undefined
		
		var lastParent = root, position = {left: 0, top: 0}
		for (var i = 0, il = nodes.length; i < il; i++)
		{
			var node = nodes[i],
				parent = node.offsetParent
			
			if (!parent)
				continue
			
			if (parent != lastParent)
			{
				lastParent = parent
				position = parent.offsetPosition(root)
			}
			
			var box =
			{
				x: node.offsetLeft + position.left,
				y: node.offsetTop + position.top,
				node: node
			}
			
			if (custom)
			{
				box.w = width
				box.h = height
			}
			else
			{
				box.w = node.offsetWidth
				box.h = node.offsetHeight
			}
			
			boxes.push(box)
		}
		
		return boxes
	},
	
	sameNodesToBoxes: function (nodes, root)
	{
		var first = nodes[0]
		if (!first)
			return []
		
		return this.nodesToBoxes(nodes, root, first.offsetWidth, first.offsetHeight)
	}
}

// Me.mixIn(EventDriven)
Me.className = myName
self[myName] = Me

})();
;(function(){

var Me =
{
	guessOS: function (ua)
	{
		if (/Windows/.test(ua))
			return ['win']
		
		if (/Macintosh|Mac OS/.test(ua))
			return ['mac']
		
		if (/Linux/.test(ua))
			return ['linux']
		
		return []
	},
	
	guessBrowser: function (ua)
	{
		function classes (n, a, b, c)
		{
			return [n, n + '-' + a, n + '-' + a + '-' + b, n + '-' + a + '-' + b + '-' + c]
		}
		
		var m = /Opera\/\d+.+Version\/(\d+)\.(\d)(\d)/.exec(ua)
		if (m)
			return classes('opera', m[1], m[2], m[3])
		
		var m = /Opera\/(\d+)\.(\d)(\d)/.exec(ua)
		if (m)
			return classes('opera', m[1], m[2], m[3])
		
		var m = /Opera (\d+)\.(\d)(\d)/.exec(ua)
		if (m)
			return classes('opera', m[1], m[2], m[3])
		
		var m = /Firefox\/(\d+)\.(\d+)\.(\d+)/.exec(ua)
		if (m)
			return classes('firefox', m[1], m[2], m[3])
		
		var m = /Firefox\/(\d+)\.(\d+)/.exec(ua)
		if (m)
			return classes('firefox', m[1], m[2], 0)
		
		var m = /MSIE (\d+)\./.exec(ua)
		if (m)
			return ['msie', 'msie-' + m[1]]
		
		var m = /Version\/(\d+)\.(\d+)\.(\d+) Safari\/\d+/.exec(ua)
		if (m)
			return classes('safari', m[1], m[2], m[3])
		
		var m = /Version\/(\d+)\.(\d+) Safari\/\d+/.exec(ua)
		if (m)
			return classes('safari', m[1], m[2], 0)
		
		var m = /Chrome\/(\d+)\.(\d+)\.(\d+)/.exec(ua)
		if (m)
			return classes('chrome', m[1], m[2], m[3])
		
		return []
	},
	
	getClassNames: function (ua)
	{
		return this.guessOS(ua).concat(this.guessBrowser(ua))
	},
	
	setupDocumentElementClassNames: function (ua)
	{
		document.documentElement.addClassNames(this.getClassNames(ua || navigator.userAgent))
	}
}

Me.className = 'UserAgent'
self[Me.className] = Me

})();


if (!document.querySelectorAll)
	$.load('/lib-0.3/core/fixes/dom-level2-selectors.js')

;(function(){

var Me =
{
	hashOfAryIndexBy: function (src, f)
	{
		var hash = {}
		for (var i = 0, il = src.length; i < il; i++)
		{
			var v = src[i]
			
			var key = f(v)
			var ary = hash[key]
			if (ary)
				ary.push(v)
			else
				hash[key] = [v]
		}
		return hash
	},
	
	hashOfAryIndexByKey: function (src, p)
	{
		var hash = {}
		for (var i = 0, il = src.length; i < il; i++)
		{
			var v = src[i]
			
			var key = v[p]
			var ary = hash[key]
			if (ary)
				ary.push(v)
			else
				hash[key] = [v]
		}
		return hash
	},
	
	hashOfAryIndexAryBy: function (src, f)
	{
		var hash = {}
		for (var i = 0, il = src.length; i < il; i++)
		{
			var v = src[i]
			
			var keys = f(v)
			
			for (var j = 0, jl = keys.length; j < jl; j++)
			{
				var key = keys[j]
				
				var ary = hash[key]
				if (ary)
					ary.push(v)
				else
					hash[key] = [v]
			}
		}
		return hash
	},
	
	hashOfAryIndexByAryKey: function (src, key)
	{
		var hash = {}
		for (var i = 0, il = src.length; i < il; i++)
		{
			var item = src[i]
			
			var ary = item[key]
			for (var j = 0, jl = ary.length; j < jl; j++)
			{
				var v = ary[j]
				var a = hash[v]
				if (a)
					a.push(item)
				else
					hash[v] = [item]
			}
		}
		return hash
	},
	
	hashIndexByAryKey: function (src, key)
	{
		var hash = {}
		for (var i = 0, il = src.length; i < il; i++)
		{
			var item = src[i]
			
			var ary = item[key]
			for (var j = 0, jl = ary.length; j < jl; j++)
				hash[ary[j]] = item
		}
		return hash
	},
	
	hashIndex: function (src)
	{
		var hash = {}
		for (var i = 0, il = src.length; i < il; i++)
			hash[src[i]] = true
		return hash
	},
	
	hashIndexKey: function (src, key)
	{
		var hash = {}
		for (var i = 0, il = src.length; i < il; i++)
		{
			var v = src[i]
			hash[v[key]] = v
		}
		return hash
	},
	
	hashIndexBy: function (src, f)
	{
		var hash = {}
		for (var i = 0, il = src.length; i < il; i++)
		{
			var v = src[i]
			hash[f(v)] = v
		}
		return hash
	},
	
	conjunction: function (arys)
	{
		var length = arys.length
		if (length == 0)
			return []
		else if (length == 1)
			return arys[0].slice()
		
		var seen = []
		for (var i = 0; i < length; i++)
		{
			var items = arys[i]
			for (var j = 0, jl = items.length; j < jl; j++)
			{
				var id = items[j]._oid
				var times = seen[id]
				if (times)
					seen[id] = times + 1
				else
					seen[id] = 1
			}
		}
		
		var first = arys[0], res = []
		for (var i = 0, il = first.length; i < il; i++)
		{
			var item = first[i]
			// if seen in all the arys
			if (seen[item._oid] == length)
				res.push(item)
		}
		
		return res
	},
	
	disjunction: function (arys)
	{
		var length = arys.length
		if (length == 0)
			return []
		else if (length == 1)
			return arys[0].slice()
		
		var res = [], seen = []
		for (var i = 0; i < length; i++)
		{
			var items = arys[i]
			for (var j = 0, jl = items.length; j < jl; j++)
			{
				var item = items[j],
					id = item._oid
				if (seen[id])
					continue
				seen[id] = true
				res.push(item)
			}
		}
		
		// res.sort(function (a, b) { return a._oid - b._oid })
		
		return res
	}
}

Me.module = {}
Me.module.staticMethods =
{
	bindPrepare: function (name, prepare)
	{
		if (prepare.alreadyFoundAndBind)
			return
		prepare.alreadyFoundAndBind = true
		
		var real = this[name]
		this[name] = function ()
		{
			this[name] = real
			prepare.apply(this)
			return real.apply(this, arguments)
		}
	},
	
	findAndBindPrepares: function ()
	{
		for (var k in this)
		{
			var prepare = this[k + 'Prepare']
			if (!prepare)
				continue
			this.bindPrepare(k, prepare)
		}
	},
	
	bake: function (data)
	{
		if (!data)
			return data
		
		var instance = data._instance
		if (!instance)
			instance = data._instance = new this(data)
		return instance
	},
	
	bakeAry: function (ary)
	{
		for (var i = 0, il = ary.length; i < il; i++)
		{
			var data = ary[i]
			
			var instance = data._instance
			if (!instance)
				instance = data._instance = new this(data)
			
			ary[i] = instance
		}
		
		return ary
	}
}

Me.className = 'DB'
self[Me.className] = Me

})();
;(function(){

var myName = 'Statistics'

var Me =
{
	magazinePromoViewed: function (promo)
	{
		this.event('magazine-promo-viewed', promo && promo.name)
	},
	
	cocktailsFilterSelected: function (name)
	{
		this.event('cocktails-filter-selected', name)
	},
	
	cocktailViewRecipe: function (cocktail)
	{
		this.event('cocktail-view-recipe', cocktail && cocktail.name)
	},
	
	cocktailViewLegend: function (cocktail)
	{
		this.event('cocktail-view-legend', cocktail && cocktail.name)
	},
	
	cocktailAddedToCalculator: function (cocktail)
	{
		this.event('cocktail-added-to-calculator', cocktail && cocktail.name)
	},
	
	ingredientPopupOpened: function (ingredient)
	{
		this.event('ingredient-popup', ingredient && ingredient.name)
	},
	
	ingredientTypedIn: function (ingredient)
	{
		this.event('ingredient-typed-in', ingredient && ingredient.name)
	},
	
	ingredientSelected: function (ingredient)
	{
		this.event('ingredient-selected', ingredient && ingredient.name)
	},
	
	combinatorQueryRaw: function (query)
	{
		this.event('combinator-query-raw', query)
	},
	
	combinatorQueryViewed: function (query)
	{
		this.event('combinator-query', query)
	},
	
	blogTagSelected: function (tag)
	{
		this.event('blog-tag-selected', tag)
	},
	
	partyPrinted: function (party)
	{
		this.path('/party/' + party.path + '/print')
	},
	
	event: function (action, label, value)
	{
		setTimeout(function () { Tracker.event('UserAction', action, label, value) }, 500)
	},
	
	path: function (path)
	{
		setTimeout(function () { Tracker.path(path) }, 500)
	}
}

Me.className = myName
self[myName] = Me

})();
;(function(){

var myName = 'Throttler'

function Me (callback, delay, timeout, invocant)
{
	this.callback = callback
	this.delay = delay
	this.timeout = timeout
	this.invocant = invocant || self
	this.delayTimer = 0
	this.timeoutTimer = 0
	
	var me = this
	this.timeoutCallback = function () { me.fire() }
	this.timerCallback = function () { me.fire() }
}

Me.prototype =
{
	call: function ()
	{
		this.args = arguments
		
		clearTimeout(this.delayTimer)
		this.delayTimer = setTimeout(this.timerCallback, this.delay)
		
		if (!this.timeoutTimer)
			this.timeoutTimer = setTimeout(this.timeoutCallback, this.timeout)
	},
	
	fire: function ()
	{
		var delayTimer = this.delayTimer
		if (delayTimer)
		{
			clearTimeout(delayTimer)
			this.delayTimer = 0
		}
		
		var timeoutTimer = this.timeoutTimer
		if (timeoutTimer)
		{
			clearTimeout(timeoutTimer)
			this.timeoutTimer = 0
		}
		
		this.callback.apply(this.invocant, this.args)
	}
}

Me.className = myName
self[myName] = Me

})();

;(function(){

function Me ()
{
	this.nodes = {}
	this.boxes = []
	this.conf =
	{
		// precalculated velocity that must be applied to go to the next page
		pageVelocity: 20,
		
		// nodes on one page, list becomes active or inactive (single) relying on this
		pageLength: 1,
		
		// just a friction to be set in the scroller space
		friction: 60,
		
		// how much soften will wave be
		soft: 10,
		
		// steps of the gridder, defaults are nive enough
		stepX: 500,
		stepY: 500,
		
		// the time to wait the next onscroll event before take any actions
		throttleSoft: 100,
		throttleHard: 500
	}
	this.constructor = Me
}

Me.className = 'LazyList'

Me.prototype =
{
	// a callback for nodes must be loaded
	load: function () {},
	
	configure: function (conf)
	{
		Object.extend(this.conf, conf)
		
		conf = this.conf
		if (conf.min === undefined)
			conf.min = conf.friction * 2
	},
	
	bind: function (nodes, cocktails)
	{
		this.nodes = nodes
		
		this.bindScroller()
		this.navigate()
		
		return this
	},
	
	bindScroller: function ()
	{
		var nodes = this.nodes,
			surface = nodes.surface, viewport = nodes.viewport
		
		var frame = this.frame = new VisibilityFrame()
		frame.setStep(this.conf.stepX, this.conf.stepY)
		
		var me = this
		frame.onmove = function (show, hide)
		{
			var load = []
			for (var i = 0; i < show.length; i++)
			{
				var box = show[i]
				if (!box.loaded)
				{
					load.push(box.node)
					box.loaded = true
				}
			}
			
			me.load(load)
		}
		
		var scroller = this.scroller = new InfiniteScroller()
		scroller.bind(viewport)
		
		var space = scroller.space
		space.add(new Kinematics.Friction(this.conf.friction))
		this.wave = space.add(new Kinematics.Wave(0, 0, 0))
	},
	
	setNodes: function (nodes, realCount)
	{
		var n = this.nodes, root = n.root, surface = n.surface, viewport = n.viewport,
			conf = this.conf
		
		var boxes = this.boxes = Boxer.sameNodesToBoxes(nodes, viewport)
		
		var frame = this.frame,
			frameWidth = viewport.offsetWidth
		
		var t = new Throttler(function (x, realX) { frame.moveTo(realX - frameWidth, 0) }, conf.throttleSoft, conf.throttleHard)
		this.scroller.onscroll = function (x, realX) { t.call(x, realX) }
		
		frame.setFrame(frameWidth * 3, viewport.offsetHeight)
		frame.setBoxes(boxes)
		frame.moveTo(0, 0)
		
		
		root.show()
		
		var scroller = this.scroller
		scroller.reset()
		
		if (realCount >= conf.pageLength)
		{
			root.removeClassName('single')
			root.removeClassName('empty')
			
			var last = boxes[realCount - 1]
			this.scroller.setWidth(last.x + last.w)
			this.wave.setup(last.w, conf.soft, conf.min)
			scroller.setMovable(true)
		}
		else if (realCount == 0)
		{
			root.removeClassName('single')
			root.addClassName('empty')
			scroller.setMovable(false)
		}
		else
		{
			root.addClassName('single')
			root.removeClassName('empty')
			scroller.setMovable(false)
		}
	},
	
	navigate: function ()
	{
		var nodes = this.nodes
		
		var me = this
		nodes.prev.addEventListener('click', function (e) { me.goPrev() }, false)
		nodes.next.addEventListener('click', function (e) { me.goNext() }, false)
	},
	
	goPrev: function ()
	{
		this.scroller.setVelocity(-this.conf.pageVelocity, 0)
		this.scroller.run()
	},
	
	goNext: function ()
	{
		this.scroller.setVelocity(this.conf.pageVelocity, 0)
		this.scroller.run()
	},
	
	jumpToNode: function (node)
	{
		var boxes = this.boxes
		SEARCH:
		{
			for (var i = 0, il = boxes.length; i < il; i++)
			{
				var box = boxes[i]
				if (box.node == node)
					break SEARCH
			}
			return
		}
		
		var box = boxes[i - i % this.conf.pageLength]
		if (box)
			this.scroller.setX(box.x)
	}
}

self[Me.className] = Me

})();
;(function(){

function Me ()
{
	this.list = new LazyList()
	this.nodes = {}
	this.conf = {pageLength: 1}
	this.previewsCache = {}
	this.constructor = Me
	this.data = {cocktails:[]}
}

Me.className = 'CocktailList'

Me.prototype =
{
	configure: function (conf)
	{
		this.conf = conf
		this.list.configure(conf)
	},
	
	bind: function (nodes)
	{
		this.nodes = nodes
		
		var list = this.list
		list.bind(nodes)
		list.load = function (nodes)
		{
			for (var i = 0, il = nodes.length; i < il; i++)
			{
				var node = nodes[i],
					image = node.img
				
				image.src = image.lazySrc
				node.removeClassName('lazy')
			}
		}
		
		return this
	},
	
	setCocktails: function (cocktails)
	{
		this.data.cocktails = cocktails
		this.render()
	},
	
	render: function ()
	{
		
		var nodes = this.nodes, root = nodes.root, surface = nodes.surface, viewport = nodes.viewport,
			cocktails = this.data.cocktails
		
		surface.empty()
		
		var nodes = []
		
		for (var i = 0, il = cocktails.length; i < il; i++)
		{
			var preview = cocktails[i].getPreviewNode(true)
			surface.appendChild(preview)
			nodes.push(preview)
		}
		
		var page = this.conf.pageLength
		if (cocktails.length >= page)
		{
			for (var j = 0; j < page; j++)
			{
				var preview = cocktails[j].getPreviewNode()
				surface.appendChild(preview)
			}
		}
		
		this.list.setNodes(nodes, cocktails.length)
	}
}

self[Me.className] = Me

})();
;(function(){

var myName = 'RoundedCorners'

function Me () {}

Me.round = function (node)
{
	node.appendChild(this.corners.cloneNode(true))
}

Me.init = function (node)
{
	var corners = this.corners = document.createElement('b')
	corners.className = 'rounding-corners'
	
	var classes = ['lt', 'rt', 'rb', 'lb']
	for (var i = 0, il = classes.length; i < il; i++)
	{
		var corner = document.createElement('b')
		corner.className = classes[i]
		corners.appendChild(corner)
	}
}

Me.className = myName
self[myName] = Me

Me.init()

})();

$.onready(function () { setTimeout(function ()
{
	GoogleAnalytics.trackPageview()
}, 250) })

String.prototype.htmlName = function () { return this.replace(/[^\w\-\.]/g, "_").toLowerCase() }

require.names =
{
	'Good': '/js/entities/Good.js'
}

