| 
          (function(global) { | 
        
        
           | 
          	'use strict' | 
        
        
           | 
              var win = window, | 
        
        
           | 
                  doc = document, | 
        
        
           | 
                  body = doc.body; | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
              /** | 
        
        
           | 
               * Default configuration properties | 
        
        
           | 
               * @type {Object} | 
        
        
           | 
               */ | 
        
        
           | 
              var defaultConfig = { | 
        
        
           | 
          
 | 
        
        
           | 
              }; | 
        
        
           | 
          
 | 
        
        
           | 
              /** | 
        
        
           | 
               * Object.assign polyfill | 
        
        
           | 
               * @param  {Object} target | 
        
        
           | 
               * @param  {Object} args | 
        
        
           | 
               * @return {Object} | 
        
        
           | 
               */ | 
        
        
           | 
              var extend = function(r, t) { | 
        
        
           | 
                  for (var e = Object(r), n = 1; n < arguments.length; n++) { | 
        
        
           | 
                      var a = arguments[n]; | 
        
        
           | 
                      if (null != a) | 
        
        
           | 
                          for (var o in a) Object.prototype.hasOwnProperty.call(a, o) && (e[o] = a[o]) | 
        
        
           | 
                  } | 
        
        
           | 
                  return e | 
        
        
           | 
              }; | 
        
        
           | 
          
 | 
        
        
           | 
              /** | 
        
        
           | 
               * Add event listener to target | 
        
        
           | 
               * @param  {Object} el | 
        
        
           | 
               * @param  {String} e | 
        
        
           | 
               * @param  {Function} fn | 
        
        
           | 
               */ | 
        
        
           | 
              var on = function(el, e, fn) { | 
        
        
           | 
                  el.addEventListener(e, fn, false); | 
        
        
           | 
              }; | 
        
        
           | 
          
 | 
        
        
           | 
              /** | 
        
        
           | 
               * Iterator helper | 
        
        
           | 
               * @param  {(Array|Object)}   arr Any object, array or array-like collection. | 
        
        
           | 
               * @param  {Function} f   The callback function | 
        
        
           | 
               * @param  {Object}   s      Change the value of this | 
        
        
           | 
               * @return {Void} | 
        
        
           | 
               */ | 
        
        
           | 
              var each = function(arr, fn, s) { | 
        
        
           | 
                  if ("[object Object]" === Object.prototype.toString.call(arr)) { | 
        
        
           | 
                      for (var d in arr) { | 
        
        
           | 
                          if (Object.prototype.hasOwnProperty.call(arr, d)) { | 
        
        
           | 
                              fn.call(s, d, arr[d]); | 
        
        
           | 
                          } | 
        
        
           | 
                      } | 
        
        
           | 
                  } else { | 
        
        
           | 
                      for (var e = 0, f = arr.length; e < f; e++) { | 
        
        
           | 
                          fn.call(s, e, arr[e]); | 
        
        
           | 
                      } | 
        
        
           | 
                  } | 
        
        
           | 
              }; | 
        
        
           | 
          
 | 
        
        
           | 
              /** | 
        
        
           | 
               * Mass assign style properties | 
        
        
           | 
               * @param  {Object} t | 
        
        
           | 
               * @param  {(String|Object)} e | 
        
        
           | 
               * @param  {String|Object} | 
        
        
           | 
               */ | 
        
        
           | 
              var style = function(t, e) { | 
        
        
           | 
                  var i = t && t.style, | 
        
        
           | 
                      n = "[object Object]" === Object.prototype.toString.call(e); | 
        
        
           | 
                  if (i) { | 
        
        
           | 
                      if (!e) return win.getComputedStyle(t); | 
        
        
           | 
                      n && each(e, function(t, e) { | 
        
        
           | 
                          t in i || (t = "-webkit-" + t), i[t] = e + ("string" == typeof e ? "" : "opacity" === t ? "" : "px") | 
        
        
           | 
                      }) | 
        
        
           | 
                  } | 
        
        
           | 
              }; | 
        
        
           | 
          
 | 
        
        
           | 
              /** | 
        
        
           | 
               * Get an element's DOMRect relative to the document instead of the viewport. | 
        
        
           | 
               * @param  {Object} t   HTMLElement | 
        
        
           | 
               * @param  {Boolean} e  Include margins | 
        
        
           | 
               * @return {Object}     Formatted DOMRect copy | 
        
        
           | 
               */ | 
        
        
           | 
              var rect = function(e) { | 
        
        
           | 
                  var t = win, | 
        
        
           | 
                      o = e.getBoundingClientRect(), | 
        
        
           | 
                      b = doc.documentElement || body.parentNode || body, | 
        
        
           | 
                      d = (void 0 !== t.pageXOffset) ? t.pageXOffset : b.scrollLeft, | 
        
        
           | 
                      n = (void 0 !== t.pageYOffset) ? t.pageYOffset : b.scrollTop; | 
        
        
           | 
                  return { | 
        
        
           | 
                      left: o.left + d, | 
        
        
           | 
                      top: o.top + n, | 
        
        
           | 
                      height: Math.round(o.height), | 
        
        
           | 
                      width: Math.round(o.width) | 
        
        
           | 
                  } | 
        
        
           | 
          	}; | 
        
        
           | 
          	 | 
        
        
           | 
          	var getRandomInt = function(min, max) { | 
        
        
           | 
          	  min = Math.ceil(min); | 
        
        
           | 
          	  max = Math.floor(max); | 
        
        
           | 
          	  return Math.floor(Math.random() * (max - min)) + min; | 
        
        
           | 
          	};	 | 
        
        
           | 
          
 | 
        
        
           | 
          	/* EMITTER */ | 
        
        
           | 
          	var Emitter = function() {}; | 
        
        
           | 
          	Emitter.prototype = { | 
        
        
           | 
          		on: function(event, fct){ | 
        
        
           | 
          			this._events = this._events || {}; | 
        
        
           | 
          			this._events[event] = this._events[event]	|| []; | 
        
        
           | 
          			this._events[event].push(fct); | 
        
        
           | 
          		}, | 
        
        
           | 
          		off: function(event, fct){ | 
        
        
           | 
          			this._events = this._events || {}; | 
        
        
           | 
          			if( event in this._events === false  )	return; | 
        
        
           | 
          			this._events[event].splice(this._events[event].indexOf(fct), 1); | 
        
        
           | 
          		}, | 
        
        
           | 
          		emit: function(event /* , args... */){ | 
        
        
           | 
          			this._events = this._events || {}; | 
        
        
           | 
          			if( event in this._events === false  )	return; | 
        
        
           | 
          			for(var i = 0; i < this._events[event].length; i++){ | 
        
        
           | 
          				this._events[event][i].apply(this, Array.prototype.slice.call(arguments, 1)); | 
        
        
           | 
          			} | 
        
        
           | 
          		} | 
        
        
           | 
          	}; | 
        
        
           | 
          
 | 
        
        
           | 
          	Emitter.mixin = function(obj) { | 
        
        
           | 
          		var props	= ['on', 'off', 'emit']; | 
        
        
           | 
          		for(var i = 0; i < props.length; i ++){ | 
        
        
           | 
          			if( typeof obj === 'function' ){ | 
        
        
           | 
          				obj.prototype[props[i]]	= Emitter.prototype[props[i]]; | 
        
        
           | 
          			}else{ | 
        
        
           | 
          				obj[props[i]] = Emitter.prototype[props[i]]; | 
        
        
           | 
          			} | 
        
        
           | 
          		} | 
        
        
           | 
          		return obj; | 
        
        
           | 
          	};	 | 
        
        
           | 
          	 | 
        
        
           | 
          	// VECTOR | 
        
        
           | 
          	function Vector(x, y) { | 
        
        
           | 
          		this.x = x; | 
        
        
           | 
          		this.y = y; | 
        
        
           | 
          	} | 
        
        
           | 
          
 | 
        
        
           | 
          	Vector.prototype = { | 
        
        
           | 
          		add: function(v) { | 
        
        
           | 
          			this.x += v.x, this.y += v.y; | 
        
        
           | 
          		},	 | 
        
        
           | 
          	};	 | 
        
        
           | 
          	 | 
        
        
           | 
          	// CARD | 
        
        
           | 
          	function Card(value, suit) { | 
        
        
           | 
          		this.value = value; | 
        
        
           | 
          		this.suit = suit; | 
        
        
           | 
          		 | 
        
        
           | 
          		this.flipped = false; | 
        
        
           | 
          		this.picture = this.value > 10; | 
        
        
           | 
          		 | 
        
        
           | 
          		switch (this.suit) { | 
        
        
           | 
          			case "hearts": | 
        
        
           | 
          			case "diamonds": | 
        
        
           | 
          				this.color = "red"; | 
        
        
           | 
          				break; | 
        
        
           | 
          			case "clubs": | 
        
        
           | 
          			case "spades": | 
        
        
           | 
          				this.color = "black"; | 
        
        
           | 
          				break;				 | 
        
        
           | 
          		} | 
        
        
           | 
          		 | 
        
        
           | 
          		var cards = ["A",2,3,4,5,6,7,8,9,10,"J","Q","K"]; | 
        
        
           | 
          
 | 
        
        
           | 
          		var template = [ | 
        
        
           | 
          			"<div class='front'><div class='value'>",cards[this.value-1],"</div><div class='value'>",cards[this.value-1],"</div><div class='middle'>" | 
        
        
           | 
          		]; | 
        
        
           | 
          
 | 
        
        
           | 
          		if (!this.picture) { | 
        
        
           | 
          			for (var i = 0; i <  this.value; i++) { | 
        
        
           | 
          				template.push("<span></span>"); | 
        
        
           | 
          			} | 
        
        
           | 
          		} | 
        
        
           | 
          
 | 
        
        
           | 
          		template.push("</div></div><div class='rear'></div>"); | 
        
        
           | 
          		 | 
        
        
           | 
          		var card = doc.createElement("div"); | 
        
        
           | 
          		card.className = `card ${this.suit} card-${(this.picture ? cards[this.value-1] : this.value)}`; | 
        
        
           | 
          		card.innerHTML = template.join(""); | 
        
        
           | 
          		 | 
        
        
           | 
          		if ( this.picture ) { | 
        
        
           | 
          			card.classList.add("picture"); | 
        
        
           | 
          		} | 
        
        
           | 
          		 | 
        
        
           | 
          		card.card = true; | 
        
        
           | 
          		 | 
        
        
           | 
          		this.el = card; | 
        
        
           | 
          	} | 
        
        
           | 
          	 | 
        
        
           | 
          	Card.prototype.flip = function() { | 
        
        
           | 
          		this.el.classList.toggle("flipped", !this.flipped); | 
        
        
           | 
          		this.el.draggable = !this.flipped; | 
        
        
           | 
          		this.flipped = !this.flipped; | 
        
        
           | 
          		 | 
        
        
           | 
          		if ( !this.flipped ) { | 
        
        
           | 
          			this.el.style.transform = ""; | 
        
        
           | 
          		} | 
        
        
           | 
          	}; | 
        
        
           | 
          	 | 
        
        
           | 
          	// PACK | 
        
        
           | 
          	function Pack() { | 
        
        
           | 
          		this.cards = []; | 
        
        
           | 
          		this.suits = ["hearts", "spades", "diamonds", "clubs"]; | 
        
        
           | 
          		 | 
        
        
           | 
          		var count = 0; | 
        
        
           | 
          		each(this.suits, function(i, suit) { | 
        
        
           | 
          			for ( var i = 1; i < 14; i++ ) { | 
        
        
           | 
          				var card = new Card(i, suit); | 
        
        
           | 
          				card.el.idx = count; | 
        
        
           | 
          				this.cards.push(card); | 
        
        
           | 
          				count++; | 
        
        
           | 
          			}			 | 
        
        
           | 
          		}, this); | 
        
        
           | 
          	} | 
        
        
           | 
          	 | 
        
        
           | 
          	Pack.prototype.shuffle = function() { | 
        
        
           | 
          		var m = this.cards.length, | 
        
        
           | 
          			t, i; | 
        
        
           | 
          		while (m) { | 
        
        
           | 
          			i = Math.floor(Math.random() * m--); | 
        
        
           | 
          			t = this.cards[m]; | 
        
        
           | 
          			this.cards[m] = this.cards[i]; | 
        
        
           | 
          			this.cards[i] = t; | 
        
        
           | 
          			 | 
        
        
           | 
          			this.cards[i].el.idx = i; | 
        
        
           | 
          			this.cards[m].el.idx = m; | 
        
        
           | 
          		} | 
        
        
           | 
          	}; | 
        
        
           | 
          	 | 
        
        
           | 
          	// GAME | 
        
        
           | 
          	function Game(el, options) { | 
        
        
           | 
          		 | 
        
        
           | 
          		if ( typeof el === "string" ) { | 
        
        
           | 
          			el = document.querySelector(el); | 
        
        
           | 
          		} | 
        
        
           | 
          		 | 
        
        
           | 
          		this.el = el; | 
        
        
           | 
          		 | 
        
        
           | 
          		this.options = extend(defaultConfig, options); | 
        
        
           | 
          		 | 
        
        
           | 
          		this.score = 0; | 
        
        
           | 
          		 | 
        
        
           | 
          		this.animationInterval = 250; | 
        
        
           | 
          		 | 
        
        
           | 
          		this.stackToColumn = false; | 
        
        
           | 
          		 | 
        
        
           | 
          		this.history = []; | 
        
        
           | 
          		 | 
        
        
           | 
          		this.pack = new Pack(); | 
        
        
           | 
          		 | 
        
        
           | 
          		Emitter.mixin(this); | 
        
        
           | 
          		 | 
        
        
           | 
          		this.render(); | 
        
        
           | 
          	} | 
        
        
           | 
          	 | 
        
        
           | 
          	Game.prototype.render = function() { | 
        
        
           | 
          		var frag = document.createDocumentFragment(); | 
        
        
           | 
          
 | 
        
        
           | 
          		this.columns = doc.createElement("div"); | 
        
        
           | 
          		this.columns.className = "columns"; | 
        
        
           | 
          
 | 
        
        
           | 
          		this.stacks = doc.createElement("div"); | 
        
        
           | 
          		this.stacks.className = "stacks"; | 
        
        
           | 
          
 | 
        
        
           | 
          		/* create stacks */ | 
        
        
           | 
          		for (var i = 0; i < 4; i++) { | 
        
        
           | 
          			var stack = doc.createElement("div"); | 
        
        
           | 
          			stack.className = "stack"; | 
        
        
           | 
          			this.stacks.appendChild(stack); | 
        
        
           | 
          		} | 
        
        
           | 
          
 | 
        
        
           | 
          		/* Create columns */ | 
        
        
           | 
          		for (var i = 0; i < 7; i++) { | 
        
        
           | 
          			var column = doc.createElement("div"); | 
        
        
           | 
          			column.className = "column"; | 
        
        
           | 
          			this.columns.appendChild(column);			 | 
        
        
           | 
          		} | 
        
        
           | 
          		 | 
        
        
           | 
          		this.dealer = doc.createElement("div"); | 
        
        
           | 
          		this.dealer.className = "dealer";		 | 
        
        
           | 
          
 | 
        
        
           | 
          		this.packArea = doc.createElement("div"); | 
        
        
           | 
          		this.packArea.className = "pack";		 | 
        
        
           | 
          
 | 
        
        
           | 
          		this.dealArea = doc.createElement("div"); | 
        
        
           | 
          		this.dealArea.className = "dealt";		 | 
        
        
           | 
          		 | 
        
        
           | 
          		this.dealer.appendChild(this.packArea); | 
        
        
           | 
          		this.dealer.appendChild(this.dealArea); | 
        
        
           | 
          		 | 
        
        
           | 
          		frag.appendChild(this.dealer); | 
        
        
           | 
          		frag.appendChild(this.stacks); | 
        
        
           | 
          		frag.appendChild(this.columns); | 
        
        
           | 
          		 | 
        
        
           | 
          		this.el.appendChild(frag); | 
        
        
           | 
          		 | 
        
        
           | 
          		this.mouse = { | 
        
        
           | 
          			x: 0, y: 0 | 
        
        
           | 
          		}; | 
        
        
           | 
          		 | 
        
        
           | 
          		var id = "https://s3-us-west-2.amazonaws.com/s.cdpn.io/86186/cards-{t}.png"; | 
        
        
           | 
          		this.images = { | 
        
        
           | 
          			clubs: id.replace("{t}", "clubs"), | 
        
        
           | 
          			spades: id.replace("{t}", "spades"), | 
        
        
           | 
          			diamonds: id.replace("{t}", "diamonds"), | 
        
        
           | 
          			hearts: id.replace("{t}", "hearts") | 
        
        
           | 
          		}; | 
        
        
           | 
          		 | 
        
        
           | 
          		each(this.images, function(i, src) { | 
        
        
           | 
          			var image = new Image(); | 
        
        
           | 
          			 | 
        
        
           | 
          			image.onload = function() { | 
        
        
           | 
          				// | 
        
        
           | 
          			}; | 
        
        
           | 
          			 | 
        
        
           | 
          			image.src = src; | 
        
        
           | 
          			 | 
        
        
           | 
          			this.images[i] = image; | 
        
        
           | 
          		}, this); | 
        
        
           | 
          		 | 
        
        
           | 
          		this.events = { | 
        
        
           | 
          			click: this.click.bind(this), | 
        
        
           | 
          			mousedown: this.mousedown.bind(this), | 
        
        
           | 
          			keydown: this.keydown.bind(this), | 
        
        
           | 
          			mouseup: this.mouseup.bind(this), | 
        
        
           | 
          			dragstart: this.dragstart.bind(this), | 
        
        
           | 
          			dragenter: this.dragenter.bind(this), | 
        
        
           | 
          			dragover: this.dragover.bind(this), | 
        
        
           | 
          			dragend: this.dragend.bind(this) | 
        
        
           | 
          		}; | 
        
        
           | 
          		 | 
        
        
           | 
          		on(this.dealer, "click", this.events.click); | 
        
        
           | 
          		 | 
        
        
           | 
          		on(this.el, "mousedown", this.events.mousedown); | 
        
        
           | 
          		on(doc, "keydown", this.events.keydown); | 
        
        
           | 
          		on(doc, "mouseup", this.events.mouseup); | 
        
        
           | 
          		 | 
        
        
           | 
          		on(doc, "dragstart", this.events.dragstart);		 | 
        
        
           | 
          		on(doc, "dragenter", this.events.dragenter); | 
        
        
           | 
          		on(doc, "dragover", this.events.dragover); | 
        
        
           | 
          		on(doc, "dragend", this.events.dragend); | 
        
        
           | 
          	}; | 
        
        
           | 
          	 | 
        
        
           | 
          	Game.prototype.click = function(e) { | 
        
        
           | 
          		var t = e.target; | 
        
        
           | 
          		if ( t.classList.contains("pack") ) { | 
        
        
           | 
          			e.stopImmediatePropagation(); | 
        
        
           | 
          			this.deal(); | 
        
        
           | 
          		} | 
        
        
           | 
          	}; | 
        
        
           | 
          	 | 
        
        
           | 
          	Game.prototype.keydown = function(e) { | 
        
        
           | 
          		var k = e.key; | 
        
        
           | 
          		 | 
        
        
           | 
          		if ( e.ctrlKey ) { | 
        
        
           | 
          			switch(k) { | 
        
        
           | 
          				case "z": | 
        
        
           | 
          					this.undo(); | 
        
        
           | 
          					break; | 
        
        
           | 
          			} | 
        
        
           | 
          		} | 
        
        
           | 
          	}; | 
        
        
           | 
          	 | 
        
        
           | 
          	Game.prototype.mousedown = function(e) { | 
        
        
           | 
          		var t = e.target.closest(".card"); | 
        
        
           | 
          		 | 
        
        
           | 
          		if ( t && t.card ) { | 
        
        
           | 
          			this.siblings = []; | 
        
        
           | 
          			var card = this.pack.cards[t.idx]; | 
        
        
           | 
          			var prev = t.previousElementSibling; | 
        
        
           | 
          			var next = t.nextElementSibling; | 
        
        
           | 
          			 | 
        
        
           | 
          			card.checked = false; | 
        
        
           | 
          
 | 
        
        
           | 
          			card.origin = { | 
        
        
           | 
          				x: e.pageX, | 
        
        
           | 
          				y: e.pageY, | 
        
        
           | 
          			}; | 
        
        
           | 
          
 | 
        
        
           | 
          			card.el.classList.add("dragging"); | 
        
        
           | 
          
 | 
        
        
           | 
          			this.activeCard = card; | 
        
        
           | 
          
 | 
        
        
           | 
          			this.startParent = card.el.parentNode; | 
        
        
           | 
          
 | 
        
        
           | 
          			if ( next ) { | 
        
        
           | 
          				var p = next.parentNode; | 
        
        
           | 
          				var idx = [].slice.call(p.children).indexOf(next); | 
        
        
           | 
          				for (var i = idx; i < p.childElementCount; i++) { | 
        
        
           | 
          					var c = p.children[i]; | 
        
        
           | 
          					c.classList.add("dragging"); | 
        
        
           | 
          					this.siblings.push(c); | 
        
        
           | 
          				}					 | 
        
        
           | 
          			} | 
        
        
           | 
          		}			 | 
        
        
           | 
          	}; | 
        
        
           | 
          
 | 
        
        
           | 
          	Game.prototype.dragstart = function(e) { | 
        
        
           | 
          		e.dataTransfer.effectAllowed = 'copy'; | 
        
        
           | 
          		e.dataTransfer.setData('text/html', ''); | 
        
        
           | 
          
 | 
        
        
           | 
          		// Create blank image to hide the ghost | 
        
        
           | 
          		var dragIcon = doc.createElement('img'); | 
        
        
           | 
          		e.dataTransfer.setDragImage(dragIcon, -10, -10);	 | 
        
        
           | 
          
 | 
        
        
           | 
          		this.dragging = true; | 
        
        
           | 
          	}; | 
        
        
           | 
          	 | 
        
        
           | 
          	Game.prototype.dragenter = function(e) { | 
        
        
           | 
          		var t = e.target; | 
        
        
           | 
          		var column = t.classList.contains("column"); | 
        
        
           | 
          		var stack = t.classList.contains("stack"); | 
        
        
           | 
          		var canDrop = t.card || column || stack; | 
        
        
           | 
          
 | 
        
        
           | 
          		if ( this.activeColumn ) { | 
        
        
           | 
          			this.activeColumn.classList.remove("over"); | 
        
        
           | 
          		} | 
        
        
           | 
          
 | 
        
        
           | 
          		if ( canDrop ) { | 
        
        
           | 
          			if ( column || stack ) { | 
        
        
           | 
          				this.activeColumn = t; | 
        
        
           | 
          			} else { | 
        
        
           | 
          				this.activeColumn = t.parentNode; | 
        
        
           | 
          			} | 
        
        
           | 
          
 | 
        
        
           | 
          			this.activeColumn.classList.add("over"); | 
        
        
           | 
          		} | 
        
        
           | 
          	}; | 
        
        
           | 
          
 | 
        
        
           | 
          	Game.prototype.dragover = function(e) { | 
        
        
           | 
          		e.preventDefault(); | 
        
        
           | 
          		e.dataTransfer.dropEffect = 'over'; | 
        
        
           | 
          
 | 
        
        
           | 
          		// Physically drag the card instead of using the D&D ghost | 
        
        
           | 
          		if ( this.activeCard && this.dragging ) { | 
        
        
           | 
          			var c = this.activeCard; | 
        
        
           | 
          			var x = e.pageX - c.origin.x; | 
        
        
           | 
          			var y = e.pageY - c.origin.y; | 
        
        
           | 
          			var css = "pointer-events: none; transform: scale(1.05, 1.05) rotateX(0deg) translate3d("+x+"px, "+y+"px, 0px);"; | 
        
        
           | 
          
 | 
        
        
           | 
          			this.activeCard.el.style.cssText = css; | 
        
        
           | 
          
 | 
        
        
           | 
          			if ( this.siblings.length ) { | 
        
        
           | 
          				each(this.siblings, function(i, card) { | 
        
        
           | 
          					card.style.cssText = css; | 
        
        
           | 
          				}, this); | 
        
        
           | 
          			} | 
        
        
           | 
          		}			 | 
        
        
           | 
          	}; | 
        
        
           | 
          
 | 
        
        
           | 
          	Game.prototype.dragend = function(e) { | 
        
        
           | 
          
 | 
        
        
           | 
          		if ( this.activeCard && this.dragging ) { | 
        
        
           | 
          
 | 
        
        
           | 
          			var c = this.activeCard; | 
        
        
           | 
          			c.el.classList.remove("dragging"); | 
        
        
           | 
          
 | 
        
        
           | 
          			var x = e.pageX - c.origin.x; | 
        
        
           | 
          			var y = e.pageY - c.origin.y; | 
        
        
           | 
          
 | 
        
        
           | 
          			c.el.style.cssText = ""; | 
        
        
           | 
          
 | 
        
        
           | 
          			if ( this.siblings.length ) { | 
        
        
           | 
          				each(this.siblings, function(i, card) { | 
        
        
           | 
          					card.classList.remove("dragging"); | 
        
        
           | 
          					card.style.cssText = ""; | 
        
        
           | 
          				}, this); | 
        
        
           | 
          			}				 | 
        
        
           | 
          
 | 
        
        
           | 
          			if ( this.activeColumn ) { | 
        
        
           | 
          				this.activeColumn.classList.remove("over"); | 
        
        
           | 
          			}			 | 
        
        
           | 
          
 | 
        
        
           | 
          			if ( this.isLegalMove() ) { | 
        
        
           | 
          				var prev = c.el.previousElementSibling; | 
        
        
           | 
          
 | 
        
        
           | 
          				// Flip the last card | 
        
        
           | 
          				if ( prev ) { | 
        
        
           | 
          					var card = this.pack.cards[prev.idx]; | 
        
        
           | 
          
 | 
        
        
           | 
          					if ( !card.flipped ) { | 
        
        
           | 
          						card.prevState = card.flipped; | 
        
        
           | 
          						card.flip(); | 
        
        
           | 
          						this.score += 5; | 
        
        
           | 
          					} | 
        
        
           | 
          				} | 
        
        
           | 
          
 | 
        
        
           | 
          				this.stackToColumn = c.el.parentNode.classList.contains("stack"); | 
        
        
           | 
          
 | 
        
        
           | 
          				this.pickCount = c.el.parentNode.childElementCount; | 
        
        
           | 
          				this.dropCount = this.activeColumn.childElementCount; | 
        
        
           | 
          
 | 
        
        
           | 
          				this.activeColumn.appendChild(c.el); | 
        
        
           | 
          
 | 
        
        
           | 
          				this.updateScore(); | 
        
        
           | 
          
 | 
        
        
           | 
          				if ( this.siblings.length ) { | 
        
        
           | 
          					each(this.siblings, function(i, card) { | 
        
        
           | 
          						if ( this.activeCard.value === 13 && | 
        
        
           | 
          							this.dropCount === 0 && | 
        
        
           | 
          							!this.startParent.classList.contains("dealt") && | 
        
        
           | 
          							c.el.parentNode.firstElementChild === c.el ) { | 
        
        
           | 
          
 | 
        
        
           | 
          						} else { | 
        
        
           | 
          							this.score += 5; | 
        
        
           | 
          						} | 
        
        
           | 
          						c.el.parentNode.appendChild(card); | 
        
        
           | 
          						card.classList.remove("dragging"); | 
        
        
           | 
          					}, this); | 
        
        
           | 
          				} | 
        
        
           | 
          				 | 
        
        
           | 
          				this.updateHistory(); | 
        
        
           | 
          				 | 
        
        
           | 
          				this.startParent.classList.toggle("empty", !this.startParent.childElementCount); | 
        
        
           | 
          				this.activeColumn.classList.toggle("empty", !this.activeColumn.childElementCount); | 
        
        
           | 
          
 | 
        
        
           | 
          				this.emit("change"); | 
        
        
           | 
          			} | 
        
        
           | 
          		} | 
        
        
           | 
          
 | 
        
        
           | 
          		if ( !this.stackToColumn ) { | 
        
        
           | 
          			this.check(); | 
        
        
           | 
          		} | 
        
        
           | 
          	}; | 
        
        
           | 
          
 | 
        
        
           | 
          	Game.prototype.mouseup = function(e) { | 
        
        
           | 
          		if ( this.activeCard ) { | 
        
        
           | 
          			this.activeCard.el.classList.remove("dragging"); | 
        
        
           | 
          			this.activeCard = false; | 
        
        
           | 
          
 | 
        
        
           | 
          			if ( this.siblings.length ) { | 
        
        
           | 
          				each(this.siblings, function(i, card) { | 
        
        
           | 
          					card.classList.remove("dragging"); | 
        
        
           | 
          				}, this); | 
        
        
           | 
          			} | 
        
        
           | 
          		} | 
        
        
           | 
          		this.hinted = false; | 
        
        
           | 
          		 | 
        
        
           | 
          
 | 
        
        
           | 
          		this.emit("change"); | 
        
        
           | 
          	}; | 
        
        
           | 
          	 | 
        
        
           | 
          	Game.prototype.updateHistory = function(card, start, end, siblings) { | 
        
        
           | 
          		var obj = {}; | 
        
        
           | 
          		 | 
        
        
           | 
          		if ( Array.isArray(card) ) { | 
        
        
           | 
          			obj.deal = true; | 
        
        
           | 
          		} else { | 
        
        
           | 
          			card = card || this.activeCard; | 
        
        
           | 
          			start = start || this.startParent; | 
        
        
           | 
          			end = end || this.activeColumn; | 
        
        
           | 
          			siblings = siblings || this.siblings; | 
        
        
           | 
          
 | 
        
        
           | 
          			// Max moves to store | 
        
        
           | 
          			var max = 10; | 
        
        
           | 
          
 | 
        
        
           | 
          			var cards = this.pack.cards; | 
        
        
           | 
          			var prev = card.el.previousElementSibling; | 
        
        
           | 
          
 | 
        
        
           | 
          			obj = { | 
        
        
           | 
          				card: card, // the card that was moved | 
        
        
           | 
          				start: start, // the original column | 
        
        
           | 
          				end: end, // the column the card was dropped in | 
        
        
           | 
          				siblings: siblings // any siblings | 
        
        
           | 
          			};	 | 
        
        
           | 
          
 | 
        
        
           | 
          			if ( prev ) { | 
        
        
           | 
          				obj.prevSibling = { | 
        
        
           | 
          					card: cards[prev.idx], | 
        
        
           | 
          					flipped: cards[prev.idx].flipped // was it hidden? | 
        
        
           | 
          				}; | 
        
        
           | 
          			} | 
        
        
           | 
          		} | 
        
        
           | 
          		 | 
        
        
           | 
          		 | 
        
        
           | 
          		// Add the move to the history | 
        
        
           | 
          		this.history.push(obj); | 
        
        
           | 
          		 | 
        
        
           | 
          		// If the number of stored moves exceeds the max allowed | 
        
        
           | 
          		// remove the oldest moves until we're at the max allowed | 
        
        
           | 
          		if ( this.history.length > max ) { | 
        
        
           | 
          			this.history.splice(0, this.history.length - max); | 
        
        
           | 
          		} | 
        
        
           | 
          	}; | 
        
        
           | 
          	 | 
        
        
           | 
          	Game.prototype.updateScore = function(start, stop) { | 
        
        
           | 
          		start = start || this.startParent; | 
        
        
           | 
          		stop = stop || this.activeColumn; | 
        
        
           | 
          		 | 
        
        
           | 
          		// Moving Kings from empty column to empty column | 
        
        
           | 
          		if ( this.dropCount === 0 &&  | 
        
        
           | 
          			this.activeCard.value === 13 && | 
        
        
           | 
          			!start.classList.contains("dealt") && | 
        
        
           | 
          			this.activeCard.el.parentNode.firstElementChild === this.activeCard.el ) { | 
        
        
           | 
          			return false; | 
        
        
           | 
          		}		 | 
        
        
           | 
          		 | 
        
        
           | 
          		// Moving from deck to column | 
        
        
           | 
          		if ( start.classList.contains("dealt") ) { | 
        
        
           | 
          			if ( stop.classList.contains("column") ) { | 
        
        
           | 
          				this.score += 5; | 
        
        
           | 
          			} | 
        
        
           | 
          		// Moving from column to column | 
        
        
           | 
          		} else if ( start.classList.contains("column") ) { | 
        
        
           | 
          			if ( stop.classList.contains("column") ) { | 
        
        
           | 
          				this.score += 3; | 
        
        
           | 
          			} | 
        
        
           | 
          		} | 
        
        
           | 
          		 | 
        
        
           | 
          		// Moving to suit stack | 
        
        
           | 
          		if ( stop.classList.contains("stack") ) { | 
        
        
           | 
          			this.score += 10; | 
        
        
           | 
          		}		 | 
        
        
           | 
          		 | 
        
        
           | 
          		// Moving from stacks to columns | 
        
        
           | 
          		if ( start.classList.contains("stack") && stop.classList.contains("column") ) { | 
        
        
           | 
          			this.score -= 10; | 
        
        
           | 
          		} | 
        
        
           | 
          	}; | 
        
        
           | 
          	 | 
        
        
           | 
          	Game.prototype.isLegalMove = function(active, column) { | 
        
        
           | 
          		active = active || this.activeCard; | 
        
        
           | 
          		column = column || this.activeColumn; | 
        
        
           | 
          		 | 
        
        
           | 
          		var last = false; | 
        
        
           | 
          		var legalMove = false; | 
        
        
           | 
          		 | 
        
        
           | 
          		var lastEl = column.lastElementChild; | 
        
        
           | 
          		var isColumn = column.classList.contains("column"); | 
        
        
           | 
          		var isPlaceholder = column.classList.contains("stack"); | 
        
        
           | 
          		 | 
        
        
           | 
          		if ( lastEl ) { | 
        
        
           | 
          			last = this.pack.cards[lastEl.idx]; | 
        
        
           | 
          		} | 
        
        
           | 
          		 | 
        
        
           | 
          		if ( isColumn ) { | 
        
        
           | 
          			if ( !column.childElementCount ) { | 
        
        
           | 
          				legalMove = active.value === 13; | 
        
        
           | 
          			} else { | 
        
        
           | 
          				legalMove = active.color !== last.color && active.value === last.value - 1; | 
        
        
           | 
          			} | 
        
        
           | 
          		} else if ( isPlaceholder ) { | 
        
        
           | 
          			if ( !column.childElementCount ) { | 
        
        
           | 
          				legalMove = active.value === 1; | 
        
        
           | 
          			} else { | 
        
        
           | 
          				legalMove = active.color === last.color && active.suit === last.suit && active.value === last.value + 1; | 
        
        
           | 
          			} | 
        
        
           | 
          		} | 
        
        
           | 
          		 | 
        
        
           | 
          		return legalMove; | 
        
        
           | 
          	}; | 
        
        
           | 
          	 | 
        
        
           | 
          	Game.prototype.undo = function() { | 
        
        
           | 
          		var index = this.history.length - 1; | 
        
        
           | 
          		 | 
        
        
           | 
          		if ( index > -1 ) { | 
        
        
           | 
          		 | 
        
        
           | 
          			var obj = this.history[index]; | 
        
        
           | 
          			 | 
        
        
           | 
          			 | 
        
        
           | 
          			if ( obj.deal ) { | 
        
        
           | 
          				// Last move was a deal | 
        
        
           | 
          				var cards = [].slice.call(this.dealArea.children); | 
        
        
           | 
          				var diff = this.dealArea.childElementCount - this.dealCount; | 
        
        
           | 
          
 | 
        
        
           | 
          				var last = cards.splice(diff, this.dealCount); | 
        
        
           | 
          
 | 
        
        
           | 
          				last.forEach(function(el) { | 
        
        
           | 
          					var card = this.pack.cards[el.idx]; | 
        
        
           | 
          					if ( card.flipped ) { | 
        
        
           | 
          						card.flip(); | 
        
        
           | 
          				this.startParent.classList.toggle("empty", !this.startParent.childElementCount); | 
        
        
           | 
          					} | 
        
        
           | 
          
 | 
        
        
           | 
          					this.packArea.appendChild(el); | 
        
        
           | 
          				}, this);				 | 
        
        
           | 
          			} else { | 
        
        
           | 
          				var card = obj.card; | 
        
        
           | 
          				var last = obj.start.lastElementChild; | 
        
        
           | 
          
 | 
        
        
           | 
          				// Hide the last card if it was flipped by moving the subsequent card | 
        
        
           | 
          				if ( last ) { | 
        
        
           | 
          					var lastCard = this.pack.cards[last.idx]; | 
        
        
           | 
          
 | 
        
        
           | 
          					if ( obj.prevSibling ) { | 
        
        
           | 
          						if ( !obj.prevSibling.prevState && lastCard.flipped ) { | 
        
        
           | 
          							lastCard.flip(); | 
        
        
           | 
          						}  | 
        
        
           | 
          					} | 
        
        
           | 
          				} | 
        
        
           | 
          
 | 
        
        
           | 
          				// Move the card back to it's original column... | 
        
        
           | 
          				obj.start.appendChild(card.el); | 
        
        
           | 
          
 | 
        
        
           | 
          				// .. as well as it's siblings | 
        
        
           | 
          				if ( obj.siblings.length ) { | 
        
        
           | 
          					obj.siblings.forEach(function(el) { | 
        
        
           | 
          						obj.start.appendChild(el); | 
        
        
           | 
          					}, this); | 
        
        
           | 
          				} | 
        
        
           | 
          
 | 
        
        
           | 
          				card.checked = false; | 
        
        
           | 
          				 | 
        
        
           | 
          				obj.start.classList.toggle("empty", !obj.start.childElementCount); | 
        
        
           | 
          				obj.end.classList.toggle("empty", !obj.end.childElementCount); | 
        
        
           | 
          			} | 
        
        
           | 
          
 | 
        
        
           | 
          			// Remove the move from the history | 
        
        
           | 
          			this.history.splice(index, 1); | 
        
        
           | 
          		} | 
        
        
           | 
          	}; | 
        
        
           | 
          	 | 
        
        
           | 
          	Game.prototype.deal = function() { | 
        
        
           | 
          		var _ = this; | 
        
        
           | 
          		var frag = document.createDocumentFragment(); | 
        
        
           | 
          		var pack = [].slice.call(this.packArea.children); | 
        
        
           | 
          		var count = pack.length; | 
        
        
           | 
          		 | 
        
        
           | 
          		if ( !count ) { | 
        
        
           | 
          			while (this.dealArea.childElementCount) { | 
        
        
           | 
          				var card = this.pack.cards[this.dealArea.lastElementChild.idx]; | 
        
        
           | 
          				card.flip(); | 
        
        
           | 
          				frag.appendChild(card.el); | 
        
        
           | 
          			} | 
        
        
           | 
          
 | 
        
        
           | 
          			this.packArea.appendChild(frag); | 
        
        
           | 
          			 | 
        
        
           | 
          			return false; | 
        
        
           | 
          		} | 
        
        
           | 
          		 | 
        
        
           | 
          		var items; | 
        
        
           | 
          		if ( count > 3 ) { | 
        
        
           | 
          			items = pack.slice(Math.max(count - 3, 1)); | 
        
        
           | 
          		} else { | 
        
        
           | 
          			items = pack; | 
        
        
           | 
          		} | 
        
        
           | 
          		 | 
        
        
           | 
          		this.dealCount = items.length; | 
        
        
           | 
          		 | 
        
        
           | 
          		each(items, function(i, c) { | 
        
        
           | 
          			if ( c ) { | 
        
        
           | 
          				var card = this.pack.cards[c.idx]; | 
        
        
           | 
          				 | 
        
        
           | 
          				var crect = rect(card.el); | 
        
        
           | 
          				var prect = rect(this.dealArea); | 
        
        
           | 
          
 | 
        
        
           | 
          				var x = crect.left - prect.left; | 
        
        
           | 
          				var y = crect.top - prect.top;				 | 
        
        
           | 
          				 | 
        
        
           | 
          				this.dealArea.appendChild(c); | 
        
        
           | 
          				 | 
        
        
           | 
          				card.el.style.cssText = "transform: translate3d("+x+"px,"+y+"px,0px) rotateY(180deg);"; | 
        
        
           | 
          				 | 
        
        
           | 
          				setTimeout(function() { | 
        
        
           | 
          					card.el.style.cssText = "transform-origin: 50% 50%;transform: translate3d(0px,0px,0px) rotateY(0deg); transition: transform "+_.animationInterval+"ms;"; | 
        
        
           | 
          					 | 
        
        
           | 
          					card.flip(); | 
        
        
           | 
          					 | 
        
        
           | 
          					card.el.style.cssText = ""; | 
        
        
           | 
          				}, this.animationInterval * i); | 
        
        
           | 
          			} | 
        
        
           | 
          		}, this); | 
        
        
           | 
          		 | 
        
        
           | 
          		this.updateHistory([]); | 
        
        
           | 
          	}; | 
        
        
           | 
          	 | 
        
        
           | 
          	Game.prototype.check = function() { | 
        
        
           | 
          		var _ = this; | 
        
        
           | 
          		this.checked = false; | 
        
        
           | 
          		var columns = [].slice.call(this.columns.children); | 
        
        
           | 
          		var holders = this.stacks.children; | 
        
        
           | 
          		 | 
        
        
           | 
          		columns.push(this.dealArea); | 
        
        
           | 
          		 | 
        
        
           | 
          		each(columns, function(i,column) { | 
        
        
           | 
          			var c = column.lastElementChild; | 
        
        
           | 
          			if ( c ) { | 
        
        
           | 
          				var card = this.pack.cards[c.idx]; | 
        
        
           | 
          				var start = card.el.parentNode; | 
        
        
           | 
          				each(holders, function(i,holder) { | 
        
        
           | 
          					if ( this.isLegalMove(card, holder) && !card.checked ) { | 
        
        
           | 
          						this.checked = true; | 
        
        
           | 
          						card.checked = true; | 
        
        
           | 
          						var prev = card.el.previousElementSibling; | 
        
        
           | 
          
 | 
        
        
           | 
          						if ( prev ) { | 
        
        
           | 
          							var prevCard = this.pack.cards[prev.idx]; | 
        
        
           | 
          							if ( !prevCard.flipped ) { | 
        
        
           | 
          								prevCard.flip(); | 
        
        
           | 
          								this.score += 5; | 
        
        
           | 
          							} | 
        
        
           | 
          						} | 
        
        
           | 
          						 | 
        
        
           | 
          						this.updateHistory(card, card.el.parentNode, holder); | 
        
        
           | 
          						 | 
        
        
           | 
          						var crect = rect(card.el); | 
        
        
           | 
          						var prect = rect(holder); | 
        
        
           | 
          						 | 
        
        
           | 
          						var x = crect.left - prect.left; | 
        
        
           | 
          						var y = crect.top - prect.top;	 | 
        
        
           | 
          						 | 
        
        
           | 
          						this.updateScore(card.el.parentNode, holder); | 
        
        
           | 
          						 | 
        
        
           | 
          						holder.appendChild(card.el); | 
        
        
           | 
          						start.classList.toggle("empty", !start.childElementCount); | 
        
        
           | 
          						 | 
        
        
           | 
          						card.el.style.cssText = "transform: translate3d("+x+"px,"+y+"px,0px);"; | 
        
        
           | 
          						 | 
        
        
           | 
          						// Repaint | 
        
        
           | 
          						card.el.offsetTop; | 
        
        
           | 
          						 | 
        
        
           | 
          						card.el.style.cssText = "transform: translate3d(0px,0px,0px); transition: transform "+this.animationInterval+"ms;"; | 
        
        
           | 
          						 | 
        
        
           | 
          						setTimeout(function() { | 
        
        
           | 
          							card.el.style.transform = ""; | 
        
        
           | 
          						}, this.animationInterval) | 
        
        
           | 
          						 | 
        
        
           | 
          						this.emit("change"); | 
        
        
           | 
          					} | 
        
        
           | 
          				}, this); | 
        
        
           | 
          			} | 
        
        
           | 
          		}, this); | 
        
        
           | 
          		 | 
        
        
           | 
          		var count = 0; | 
        
        
           | 
          		each(this.stacks.children, function(i, stack) { | 
        
        
           | 
          			count += stack.childElementCount; | 
        
        
           | 
          		}); | 
        
        
           | 
          		 | 
        
        
           | 
          		this.won = false; | 
        
        
           | 
          		if ( count === 52 ) { | 
        
        
           | 
          			setTimeout(function() { | 
        
        
           | 
          				_.win(); | 
        
        
           | 
          			}, this.animationInterval); | 
        
        
           | 
          			return false; | 
        
        
           | 
          		} | 
        
        
           | 
          		 | 
        
        
           | 
          		if ( this.checked ) { | 
        
        
           | 
          			setTimeout(function() { | 
        
        
           | 
          				_.check(); | 
        
        
           | 
          			}, this.animationInterval); | 
        
        
           | 
          		} | 
        
        
           | 
          	}; | 
        
        
           | 
          	 | 
        
        
           | 
          	Game.prototype.start = function() { | 
        
        
           | 
          		var columns = 7; | 
        
        
           | 
          		var current = 0; | 
        
        
           | 
          		var start = 0; | 
        
        
           | 
          
 | 
        
        
           | 
          		// Minimize DOM changes | 
        
        
           | 
          		var columns = this.columns; | 
        
        
           | 
          		var pack = this.packArea; | 
        
        
           | 
          		 | 
        
        
           | 
          		this.reset(); | 
        
        
           | 
          
 | 
        
        
           | 
          		// Shuffle | 
        
        
           | 
          		this.pack.shuffle(); | 
        
        
           | 
          		 | 
        
        
           | 
          		for (var i = 0; i < 28; i++) { | 
        
        
           | 
          			var card = this.pack.cards[i]; | 
        
        
           | 
          
 | 
        
        
           | 
          			/* append the card to the column */ | 
        
        
           | 
          			columns.children[current].appendChild(card.el); | 
        
        
           | 
          			 | 
        
        
           | 
          			/* flip the card if it is the first one */ | 
        
        
           | 
          			if (start === current) { | 
        
        
           | 
          				card.flip(); | 
        
        
           | 
          			} | 
        
        
           | 
          
 | 
        
        
           | 
          			/* increment the column we're dropping the card in to */ | 
        
        
           | 
          			current++; | 
        
        
           | 
          
 | 
        
        
           | 
          			/* increment start position */ | 
        
        
           | 
          			if (current === 7) { | 
        
        
           | 
          				start++; | 
        
        
           | 
          				current = start; | 
        
        
           | 
          			} | 
        
        
           | 
          		} | 
        
        
           | 
          		 | 
        
        
           | 
          		for (var i = 28; i < 52; i++) { | 
        
        
           | 
          			pack.appendChild(this.pack.cards[i].el); | 
        
        
           | 
          		} | 
        
        
           | 
          
 | 
        
        
           | 
          		this.packArea.parentNode.replaceChild(pack, this.packArea); | 
        
        
           | 
          		this.columns.parentNode.replaceChild(columns, this.columns); | 
        
        
           | 
          		 | 
        
        
           | 
          		this.packArea = pack; | 
        
        
           | 
          		this.columns = columns; | 
        
        
           | 
          		 | 
        
        
           | 
          		this.emit("start"); | 
        
        
           | 
          	}; | 
        
        
           | 
          	 | 
        
        
           | 
          	Game.prototype.hint = function() { | 
        
        
           | 
          		this.hinted = false; | 
        
        
           | 
          		var columns = [].slice.call(this.columns.children); | 
        
        
           | 
          		 | 
        
        
           | 
          		columns.push(this.dealArea); | 
        
        
           | 
          		 | 
        
        
           | 
          		each(this.stacks, function(i, stack) { | 
        
        
           | 
          			columns.push(stack); | 
        
        
           | 
          		}); | 
        
        
           | 
          		 | 
        
        
           | 
          		each(columns, function(i,column) { | 
        
        
           | 
          			var c; | 
        
        
           | 
          			if ( column === this.dealArea ) { | 
        
        
           | 
          				c = column.lastElementChild; | 
        
        
           | 
          			} else { | 
        
        
           | 
          				c = column.getElementsByClassName("flipped")[0]; | 
        
        
           | 
          			} | 
        
        
           | 
          
 | 
        
        
           | 
          			if ( c ) { | 
        
        
           | 
          				var card = this.pack.cards[c.idx]; | 
        
        
           | 
          				var isLast, siblings = []; | 
        
        
           | 
          				var nodeIndex = [].slice.call(card.el.parentNode.children).indexOf(card.el); | 
        
        
           | 
          				 | 
        
        
           | 
          				if ( card.el.previousElementSibling ) { | 
        
        
           | 
          					if ( card.el.parentNode === this.dealArea ) { | 
        
        
           | 
          						isLast = true; | 
        
        
           | 
          					} else { | 
        
        
           | 
          						isLast = !card.el.previousElementSibling.classList.contains("flipped") | 
        
        
           | 
          					} | 
        
        
           | 
          				} | 
        
        
           | 
          				 | 
        
        
           | 
          				if ( card.value === 1 || card.el.parentNode.childElementCount === 1 ) { | 
        
        
           | 
          					isLast = true; | 
        
        
           | 
          				} | 
        
        
           | 
          				 | 
        
        
           | 
          				if ( card.value === 13 && card.el.parentNode.classList.contains("column") && card.el.parentNode.childElementCount === 1 ) { | 
        
        
           | 
          					return false; | 
        
        
           | 
          				} | 
        
        
           | 
          				 | 
        
        
           | 
          				each(card.el.parentNode.children, function(i, node) { | 
        
        
           | 
          					if ( i > nodeIndex ) { | 
        
        
           | 
          						siblings.push(node); | 
        
        
           | 
          					} | 
        
        
           | 
          				});				 | 
        
        
           | 
          
 | 
        
        
           | 
          				each(columns, function(idx,col) { | 
        
        
           | 
          					if ( this.isLegalMove(card, col) && isLast && !this.hinted ) { | 
        
        
           | 
          						var lastCard, last = col.lastElementChild; | 
        
        
           | 
          						if ( last ) { | 
        
        
           | 
          							lastCard = this.pack.cards[last.idx].el; | 
        
        
           | 
          						} else { | 
        
        
           | 
          							if ( card.value === 13 ) { | 
        
        
           | 
          								lastCard = col; | 
        
        
           | 
          							} | 
        
        
           | 
          						} | 
        
        
           | 
          						 | 
        
        
           | 
          						card.el.classList.add("hint"); | 
        
        
           | 
          						 | 
        
        
           | 
          						if ( siblings.length ) { | 
        
        
           | 
          							each(siblings, function(i, node) { | 
        
        
           | 
          								node.classList.add("hint"); | 
        
        
           | 
          							}); | 
        
        
           | 
          						} | 
        
        
           | 
          						 | 
        
        
           | 
          						setTimeout(function() { | 
        
        
           | 
          							card.el.classList.remove("hint"); | 
        
        
           | 
          							 | 
        
        
           | 
          							if ( siblings.length ) { | 
        
        
           | 
          								each(siblings, function(i, node) { | 
        
        
           | 
          									node.classList.remove("hint"); | 
        
        
           | 
          								}); | 
        
        
           | 
          							}							 | 
        
        
           | 
          							 | 
        
        
           | 
          							lastCard.classList.add("hint"); | 
        
        
           | 
          							 | 
        
        
           | 
          							setTimeout(function() { | 
        
        
           | 
          								lastCard.classList.remove("hint"); | 
        
        
           | 
          							}, 500);							 | 
        
        
           | 
          						}, 500); | 
        
        
           | 
          						 | 
        
        
           | 
          						this.hinted = true; | 
        
        
           | 
          						this.score -= 20; | 
        
        
           | 
          					} | 
        
        
           | 
          				}, this); | 
        
        
           | 
          			} | 
        
        
           | 
          		}, this); | 
        
        
           | 
          	}; | 
        
        
           | 
          	 | 
        
        
           | 
          	Game.prototype.reset = function() { | 
        
        
           | 
          		 | 
        
        
           | 
          		this.score = 0; | 
        
        
           | 
          		this.history = [];		 | 
        
        
           | 
          		 | 
        
        
           | 
          		if ( this.won ) { | 
        
        
           | 
          			this.won = false; | 
        
        
           | 
          			document.body.removeChild(this.canvas); | 
        
        
           | 
          		} | 
        
        
           | 
          		 | 
        
        
           | 
          		this.pack.cards.forEach(function(card) { | 
        
        
           | 
          			if ( card.flipped ) { | 
        
        
           | 
          				card.flip(); | 
        
        
           | 
          			}			 | 
        
        
           | 
          			card.checked = false; | 
        
        
           | 
          		}); | 
        
        
           | 
          		 | 
        
        
           | 
          		[].slice.call(this.columns.children).forEach(function(column) { | 
        
        
           | 
          			column.classList.remove("empty"); | 
        
        
           | 
          		}); | 
        
        
           | 
          		 | 
        
        
           | 
          		[].slice.call(this.stacks.children).forEach(function(stack) { | 
        
        
           | 
          			stack.classList.remove("empty"); | 
        
        
           | 
          		});			 | 
        
        
           | 
          		 | 
        
        
           | 
          	}; | 
        
        
           | 
          	 | 
        
        
           | 
          	Game.prototype.win = function() { | 
        
        
           | 
          		if ( this.won ) { | 
        
        
           | 
          			return false; | 
        
        
           | 
          		} | 
        
        
           | 
          		 | 
        
        
           | 
          		this.won = true; | 
        
        
           | 
          		 | 
        
        
           | 
          		var rects = []; | 
        
        
           | 
          		var suits = []; | 
        
        
           | 
          		 | 
        
        
           | 
          		this.pack.cards.forEach(function(card) { | 
        
        
           | 
          			card.el.style.transform = ""; | 
        
        
           | 
          		}); | 
        
        
           | 
          				 | 
        
        
           | 
          		 | 
        
        
           | 
          		each(this.stacks.children, function(i, stack) { | 
        
        
           | 
          			rects.push(rect(stack)); | 
        
        
           | 
          			 | 
        
        
           | 
          			var last = stack.lastElementChild; | 
        
        
           | 
          			var card = this.pack.cards[last.idx]; | 
        
        
           | 
          			 | 
        
        
           | 
          			suits.push(card.suit); | 
        
        
           | 
          		}, this); | 
        
        
           | 
          
 | 
        
        
           | 
          		this.canvas = document.createElement("canvas"); | 
        
        
           | 
          		var that = this; | 
        
        
           | 
          		var ctx = this.canvas.getContext("2d"); | 
        
        
           | 
          		var w = this.canvas.width = window.innerWidth; | 
        
        
           | 
          		var h = this.canvas.height = window.innerHeight; | 
        
        
           | 
          		var gravity, wind; | 
        
        
           | 
          		var pos = new Vector(rects[0].left, rects[0].top); | 
        
        
           | 
          		var vel = new Vector(0, -getRandomInt(25,30)); | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          		var sWidth = 125; | 
        
        
           | 
          		var sHeight = 188; | 
        
        
           | 
          		 | 
        
        
           | 
          		var frame = null; | 
        
        
           | 
          		var x = 0; | 
        
        
           | 
          		var sx = sWidth * 12; | 
        
        
           | 
          		var sy = 0;	 | 
        
        
           | 
          		 | 
        
        
           | 
          		var init = function() { | 
        
        
           | 
          			document.body.appendChild(that.canvas); | 
        
        
           | 
          			setGravity(); | 
        
        
           | 
          			setWind(); | 
        
        
           | 
          			draw();	 | 
        
        
           | 
          		} | 
        
        
           | 
          
 | 
        
        
           | 
          		var setGravity = function() { | 
        
        
           | 
          			gravity = new Vector(0, getRandomInt(1, 9)); | 
        
        
           | 
          		}	 | 
        
        
           | 
          
 | 
        
        
           | 
          		var setWind = function() { | 
        
        
           | 
          			var a = [-1,1]; | 
        
        
           | 
          			var r = a[Math.floor(Math.random() * a.length)] | 
        
        
           | 
          			var w = getRandomInt(5,15); | 
        
        
           | 
          			wind = new Vector(w * r, 0); | 
        
        
           | 
          		} | 
        
        
           | 
          		 | 
        
        
           | 
          		var outline = function(p, w, h) { | 
        
        
           | 
          			 | 
        
        
           | 
          			var r = 5; | 
        
        
           | 
          			 | 
        
        
           | 
          			var points = [ | 
        
        
           | 
          				[p.x + r, p.y], | 
        
        
           | 
          				[p.x + w - r, p.y], | 
        
        
           | 
          				[p.x + w, p.y + r], | 
        
        
           | 
          				[p.x + w, (p.y + h) - r], | 
        
        
           | 
          				[p.x + w - r, p.y + h], | 
        
        
           | 
          				[p.x + r, p.y + h], | 
        
        
           | 
          				[p.x, (p.y + h) - r], | 
        
        
           | 
          				[p.x, p.y + r], | 
        
        
           | 
          			]; | 
        
        
           | 
          			 | 
        
        
           | 
          			ctx.beginPath(); | 
        
        
           | 
          			ctx.lineWidth = 2; | 
        
        
           | 
          			ctx.strokeStyle = "#333"; | 
        
        
           | 
          			 | 
        
        
           | 
          			// Top | 
        
        
           | 
          			ctx.moveTo(points[0][0], points[0][1]); | 
        
        
           | 
          			ctx.lineTo(points[1][0], points[1][1]); | 
        
        
           | 
          
 | 
        
        
           | 
          			// Top right corner | 
        
        
           | 
          			ctx.arc(points[1][0], points[2][1], r, 1.5 * Math.PI, 2 * Math.PI); | 
        
        
           | 
          
 | 
        
        
           | 
          			// Right side | 
        
        
           | 
          			ctx.moveTo(points[2][0], points[2][1]); | 
        
        
           | 
          			ctx.lineTo(points[3][0], points[3][1]); | 
        
        
           | 
          			 | 
        
        
           | 
          			// Bottom right corner | 
        
        
           | 
          			ctx.arc(points[4][0], points[3][1], r, 2 * Math.PI, 2.5 * Math.PI);	 | 
        
        
           | 
          			 | 
        
        
           | 
          			// Bottom | 
        
        
           | 
          			ctx.moveTo(points[4][0], points[4][1]); | 
        
        
           | 
          			ctx.lineTo(points[5][0], points[5][1]); | 
        
        
           | 
          			 | 
        
        
           | 
          			// Bottom left corner | 
        
        
           | 
          			ctx.arc(p.x + r, p.y + h - r, r, 2.5 * Math.PI, 3 * Math.PI);		 | 
        
        
           | 
          			 | 
        
        
           | 
          			// Left side | 
        
        
           | 
          			ctx.moveTo(points[6][0], points[6][1]); | 
        
        
           | 
          			ctx.lineTo(points[7][0], points[7][1]); | 
        
        
           | 
          			 | 
        
        
           | 
          			// Top left | 
        
        
           | 
          			ctx.arc(points[5][0], points[7][1], r, 3 * Math.PI, 3.5 * Math.PI); | 
        
        
           | 
          			 | 
        
        
           | 
          			ctx.stroke();				 | 
        
        
           | 
          		}; | 
        
        
           | 
          
 | 
        
        
           | 
          		var draw = function() { | 
        
        
           | 
          
 | 
        
        
           | 
          			frame = requestAnimationFrame(draw); | 
        
        
           | 
          
 | 
        
        
           | 
          			var img = that.images[suits[x]]; | 
        
        
           | 
          
 | 
        
        
           | 
          			var dWidth = sWidth; | 
        
        
           | 
          			var dHeight = sHeight; | 
        
        
           | 
          
 | 
        
        
           | 
          			vel.add(gravity); | 
        
        
           | 
          
 | 
        
        
           | 
          			pos.add(vel); | 
        
        
           | 
          			pos.add(wind); | 
        
        
           | 
          
 | 
        
        
           | 
          			if (pos.y >= h - sHeight) { | 
        
        
           | 
          				pos.y = h - sHeight; | 
        
        
           | 
          				vel.y = -vel.y; | 
        
        
           | 
          			}	 | 
        
        
           | 
          			 | 
        
        
           | 
          			ctx.fillStyle="#FFFFFF"; | 
        
        
           | 
          			ctx.drawImage(img, sx, sy, sWidth, sHeight, pos.x, pos.y, dWidth, dHeight);			 | 
        
        
           | 
          			 | 
        
        
           | 
          			outline(pos, sWidth, sHeight);		 | 
        
        
           | 
          
 | 
        
        
           | 
          			if ( pos.x < 0 - sWidth || pos.x > w ) { | 
        
        
           | 
          				 | 
        
        
           | 
          				if ( x < 3 ) { | 
        
        
           | 
          					x++; | 
        
        
           | 
          				} else { | 
        
        
           | 
          					x = 0; | 
        
        
           | 
          					sx -= sWidth; | 
        
        
           | 
          				} | 
        
        
           | 
          				 | 
        
        
           | 
          				if ( sx > 0 - sWidth ) { | 
        
        
           | 
          					pos = new Vector(rects[x].left, rects[x].top); | 
        
        
           | 
          					vel = new Vector(0, -getRandomInt(25,30)); | 
        
        
           | 
          					setGravity(); | 
        
        
           | 
          					setWind(); | 
        
        
           | 
          				} | 
        
        
           | 
          			}	 | 
        
        
           | 
          		} | 
        
        
           | 
          		 | 
        
        
           | 
          		init(); | 
        
        
           | 
          		setGravity(); | 
        
        
           | 
          		setWind();		 | 
        
        
           | 
          	}; | 
        
        
           | 
          	 | 
        
        
           | 
          	Game.prototype.cheat = function() { | 
        
        
           | 
          		var that = this; | 
        
        
           | 
          		this.checked = false; | 
        
        
           | 
          		var columns = [].slice.call(this.columns.children); | 
        
        
           | 
          		var holders = this.stacks.children; | 
        
        
           | 
          		 | 
        
        
           | 
          		columns.push(this.dealArea); | 
        
        
           | 
          		 | 
        
        
           | 
          		each(this.pack.suits, function(i, suit) { | 
        
        
           | 
          			var el, card, s; | 
        
        
           | 
          			 | 
        
        
           | 
          			for( var n = 1; n < 14; n++ ) { | 
        
        
           | 
          				 | 
        
        
           | 
          				s = n; | 
        
        
           | 
          				 | 
        
        
           | 
          				if ( n > 10 ) { | 
        
        
           | 
          					switch(n) { | 
        
        
           | 
          						case 11: | 
        
        
           | 
          							s = "J"; | 
        
        
           | 
          							break; | 
        
        
           | 
          						case 12: | 
        
        
           | 
          							s = "Q"; | 
        
        
           | 
          							break; | 
        
        
           | 
          						case 13: | 
        
        
           | 
          							s = "K"; | 
        
        
           | 
          							break;							 | 
        
        
           | 
          					} | 
        
        
           | 
          				} | 
        
        
           | 
          				 | 
        
        
           | 
          				el = document.querySelector(`.card.${suit}.card-${s}`); | 
        
        
           | 
          				 | 
        
        
           | 
          				card = this.pack.cards[el.idx]; | 
        
        
           | 
          				 | 
        
        
           | 
          				var prev = card.el.previousElementSibling; | 
        
        
           | 
          				 | 
        
        
           | 
          				if ( !card.flipped && card.el.parentNode !== this.packArea ) { | 
        
        
           | 
          					card.flip(); | 
        
        
           | 
          				} | 
        
        
           | 
          
 | 
        
        
           | 
          				if ( prev && card.el.parentNode !== this.packArea ) { | 
        
        
           | 
          					var prevCard = this.pack.cards[prev.idx]; | 
        
        
           | 
          					if ( !prevCard.flipped ) { | 
        
        
           | 
          						prevCard.flip(); | 
        
        
           | 
          						this.score += 5; | 
        
        
           | 
          					} | 
        
        
           | 
          				} | 
        
        
           | 
          
 | 
        
        
           | 
          				var crect = rect(card.el); | 
        
        
           | 
          				var prect = rect(holders[i]); | 
        
        
           | 
          
 | 
        
        
           | 
          				var x = crect.left - prect.left; | 
        
        
           | 
          				var y = crect.top - prect.top;	 | 
        
        
           | 
          
 | 
        
        
           | 
          				holders[i].appendChild(card.el); | 
        
        
           | 
          
 | 
        
        
           | 
          				card.el.style.cssText = "transform: translate3d("+x+"px,"+y+"px,0px);"; | 
        
        
           | 
          
 | 
        
        
           | 
          				// Repaint | 
        
        
           | 
          				card.el.offsetTop; | 
        
        
           | 
          
 | 
        
        
           | 
          				card.el.style.cssText = "transform: translate3d(0px,0px,0px); transition: transform "+this.animationInterval+"ms;"; | 
        
        
           | 
          				 | 
        
        
           | 
          				setTimeout(function() { | 
        
        
           | 
          					card.el.style.transform = ""; | 
        
        
           | 
          				}, this.animationInterval)				 | 
        
        
           | 
          			} | 
        
        
           | 
          		}, this); | 
        
        
           | 
          		 | 
        
        
           | 
          		setTimeout(function() { | 
        
        
           | 
          			that.win(); | 
        
        
           | 
          		}, this.animationInterval); | 
        
        
           | 
          	}; | 
        
        
           | 
          
 | 
        
        
           | 
          	global.Game = Game; | 
        
        
           | 
          }(this)); | 
        
        
           | 
          
 | 
        
        
           | 
          var controls = document.getElementById("controls"); | 
        
        
           | 
          var score = document.getElementById("score"); | 
        
        
           | 
          var game = new Game("#container"); | 
        
        
           | 
          
 | 
        
        
           | 
          game.start(); | 
        
        
           | 
          
 | 
        
        
           | 
          game.on("start", function() { | 
        
        
           | 
          	score.textContent = "Score: " + this.score; | 
        
        
           | 
          }); | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          game.on("change", function() { | 
        
        
           | 
          	score.textContent = "Score: " + this.score; | 
        
        
           | 
          }); | 
        
        
           | 
          
 | 
        
        
           | 
          controls.addEventListener("click", function(e) { | 
        
        
           | 
          	var t = e.target; | 
        
        
           | 
          	if ( t.nodeName === "BUTTON" ) { | 
        
        
           | 
          		var action = t.getAttribute("data-action"); | 
        
        
           | 
          		game[action](); | 
        
        
           | 
          	} | 
        
        
           | 
          }, false); |