<commit_before>if (!window.$) {
	for (var key in window) {
		if (key.substr(0, 6).toLowerCase() == 'jquery') {
			window.$ = window[key].handle;
			break;
		}
	}
}

if (window.$) {
	var options, radData, kanData, prevItem, bookmarks;

	function updateBookmark(thread, page) {
		bookmarks[thread] = page;
		localStorage.setItem('bookmarks', JSON.stringify(bookmarks));
	}

	function levelIndex(item, currRad, currKan) {
		if (item.rad) {
			if (currRad && currRad.indexOf(item.en[0]) !== -1)
				return 0;
		} else if (item.kan) {
			if (currKan && currKan.indexOf(item.kan) !== -1)
				return 1;
		}
		return 2;
	}

	// Lesson/Review queuing
	function setLessonsQueue(needsUpdating) {
		if (options.sort_rad_i)
			return;
		var revArr = $.jStorage.get('l/activeQueue');
		if (!revArr)
			return;
		var storedReviews = $.jStorage.get("l/lessonQueue");
		if (!needsUpdating) {
			for (var i = 0; i < storedReviews.length; ++i) {
				var item = storedReviews[i];
				if (item && item.rad) {
					needsUpdating = true;
					break;
				}
			}
		}
		if (!needsUpdating)
			return;

		var itemsArrays = [[], [], []];
		storedReviews = storedReviews.concat(revArr);
		var currCount = 0;
		for (var i = 0; i < storedReviews.length; ++i) {
			var item = storedReviews[i];
			if (item && item.rad) {
				console.log(item);
				itemsArrays[0].push(item);
				++currCount;
			} else {
				itemsArrays[2].push(item);
			}
		}
		var actQueue = itemsArrays[0].concat(itemsArrays[1]);
		$.jStorage.set('l/activeQueue', actQueue);
		$.jStorage.set('l/lessonQueue', itemsArrays[2]);
	}

	function setReviewQueue(needsUpdating) {
		var currRad = !options.sort_rad_i ? localStorage.getItem('radicalData') : null;
		var currKan = options.sort_kan ? localStorage.getItem('kanjiData') : null;
		var storedReviews = $.jStorage.get("reviewQueue");
		var checkBurn = false; // !options.sort_burn_i; TODO fix
		if (!needsUpdating) {
			for (var i = 0; i < storedReviews.length; ++i) {
				var item = storedReviews[i];
				if (!item)
					continue;
				if ((checkBurn && item.srs == 8) || levelIndex(item, currRad, currKan) !== 2) {
					needsUpdating = true;
					break;
				}
			}
		}
		if (!needsUpdating)
			return;

		var itemsArrays = [[], [], []];
		var revArr = $.jStorage.get('activeQueue');
		if (!revArr)
			return;
		storedReviews = storedReviews.concat(revArr);
		var currCount = 0, burnCount = 0;
		for (var i = 0; i < storedReviews.length; ++i) {
			var item = storedReviews[i];
			if (item) {
				var li;
				if (checkBurn && item.srs == 8) {
					li = 1;
					++burnCount;
				} else {
					li = levelIndex(item, currRad, null);
					if (li < 2)
						++currCount;
				}
				itemsArrays[li].push(item);
			}
		}
		var actQueue = itemsArrays[0].concat(itemsArrays[1]);
		$.jStorage.set('activeQueue', actQueue);
		$.jStorage.set('reviewQueue', itemsArrays[2]);
		$('#question #current-count').text(currCount);
		$('#question #burn-count').text(burnCount);
		$('#question #current-stats').toggle(currCount > 0);
		$('#question #burn-stats').toggle(burnCount > 0);
	}

	function onItemFinished(key, action) {
		if (!prevItem)
			return;
		if (prevItem.srs == 8) {
			var currText = $('#question #burn-count');
			var currValue = parseInt(currText.text());
			if (currValue > 1) {
				currText.text(currValue - 1);
			} else {
				$('#question #burn-stats').hide();
			}
		} else {
			var lIdx = levelIndex(prevItem, radData, kanData);
			if (lIdx < 2) {
				var currText = $('#question #current-count');
				var currValue = parseInt(currText.text());
				if (currValue > 1) {
					currText.text(currValue - 1);
				} else {
					$('#question #current-stats').hide();
				}
			}
		}
	}

	if ($.jStorage && $('#lessons').length == 0) {
		var kunyomi_list = [
			"売","草","戸","糸","皿","竹","皮","花","耳","又","雪","打","村","貝","赤","夏","兄","広","父","冬","久","谷","川","田","目","夕","付","左","手","合","四","犬","引","玉","申","々","投","雲","森","朝","紙","首","何","雨","色","里","羽","池","黄","星","麦","母","丸","見","右","虫","石","林","氷","考","飲","泳","顔","軽","葉","頭","起","読","横","追","島","待","受","指","拾","伝","仲","寒","湯","歯","昔","始","持","乗","物","良","声","方","鳴","答","橋","緑","鏡","様","悲","祭","暑","着","皆","場","買","泣","猫","秋","帰","晴","昼","春","浅","寺","岩","坂","浜","芽","甘","替","奪","磨","貸","埼","滝","翔","懐","遠","遊","荒","俺","鼻","塩","熊","戻","梅","箱","荷","喜","笑","取","浴","若","舌","胸","忙","困","底","臭","穴","岡","尻","浮","焼","株","渡","宮","違","狭","届","腰","肩","値","割","傘","側","呼","抜","針","掛","城","細","厚","藤","靴","娘","江","詰","渇","押","枕","悩","酢","縦","幾","亀","彼","卵","飼","込","机","窓","灰","汗","杉","爪","裏","巣","捨","鍋","払","埋","吐","芋","恥","豚","緩","寝","抱","繰","伸","津","幅","沖","扱","宜","控","壁","片","稲","駆","吹","堀","桃","瀬","蛍","虎","蜂","桜","枠","賭","髪","梨","伺","畑","涙","堅","綱","潟","誰","笠","嵐","姫","謎","刃","侍","曇","呪","也","頃","舟","肌","棚","釣","腕","芝","袋","柄","琴","沼","垣","叱",
			"墨","癖","吾","鍵","猿","箸","霧","唇","虹","爽","脇","咲","踊","闇","霜","蚊","貼","蛇","煮","駒","桑","鰐","蟹","淀"
		];
		radData = localStorage.getItem('radicalData');
		kanData = localStorage.getItem('kanjiData');
		$.jStorage.listenKeyChange('lastItems', onItemFinished);
		$('input').attr('autocomplete', 'off');
		$.jStorage.listenKeyChange('currentItem', function(key, action) {
			var item = $.jStorage.get(key);
			if (!item)
				return;
			var burning = item.srs == 8;
		    var lIdx = levelIndex(item, radData, kanData);
			$('.icon-chevron-right').toggleClass('icon-burn burning', burning);
			$('.icon-chevron-right').toggleClass('icon-level active-level', !burning && lIdx !== 2);
			if (lIdx === 0) {
				console.log(item.rad + ': ' + item.en[0]);
			} else if (lIdx === 1) {
				var read = item.emph === 'onyomi' ? item.on : item.kun;
				console.log(item.kan + ': ' + item.en[0] + '  ' + read);
			}

			var kChar = item.kan;
			if (kChar) {
				setTimeout(function() {
					var quest = $('#question-type.reading');
					if (quest.length !== 0) {
						var found = 'On';
						for (var i = 0; i < kunyomi_list.length; i++) {
						    if (kunyomi_list[i] === kChar) {
						        found = 'Kun';
						        break;
						    }
						}
						quest.html('
' + found + "'yomi Reading?
");
					}
				}, 0);
			}
			prevItem = item;
		});
	}

	// Page load
	$(function() {
		var stored = $('#customizer').html();
		if (stored && stored.length !== 0) {
			options = JSON.parse(stored);
		} else {
			options = {};
		}
		if ($.jStorage) {
			if (document.getElementById('#lessons')) {
				setLessonsQueue(true);
				setTimeout(setLessonsQueue, 2000);
				return;
			}
			if (document.getElementById('#reviews')) {
				setReviewQueue(true);
				setTimeout(function() { setReviewQueue(true); }, 5000);
				setInterval(setReviewQueue, 60000);
				return;
			}
		}
		var revDisplay = $('li.reviews a');
		if (revDisplay && revDisplay.find('span').text() != '0') {
			revDisplay.attr('href', '/review/session');
		}
		revDisplay = $('li.lessons a');
		if (revDisplay && revDisplay.find('span').text() != '0') {
			revDisplay.attr('href', '/lesson/session');
		}

		var splitted = document.location.pathname.split('/');
		var siteSection = splitted[1];
		var isHome = !siteSection || siteSection === 'dashboard';
		if (isHome || siteSection === 'chat') {
			bookmarks = localStorage.getItem('bookmarks');
			if (bookmarks) {
				bookmarks = JSON.parse(bookmarks);
			} else {
				bookmarks = {};
			}
		}
		if (isHome) {
			$('.forum-topics-list table tr td:first-child a:first-child').each(function() {
				var pageUrl = $(this).attr('href');
				var tid = pageUrl.split('/')[3];
				var storedPage = bookmarks[tid];
				if (storedPage)
					$(this).attr('href', pageUrl + '/page/' + storedPage);
			});
			var title = 'radicalData';
			var idx = 0;
			$('.lattice-single-character ul').each(function() {
				var stor = [];
				if (idx === 1) {
					// stor = $(this).find('li').text().split('');
					return;
				} else {
					$(this).find('li').each(function() {
						var iName;
						iName = $(this).find('a').attr('data-original-title');
						stor.push(iName);
					});
				}
				localStorage.setItem(title, stor);
				title = 'kanjiData';
				++idx;
			});
		} else if (siteSection === 'chat') {
			var pageNumber = splitted[5];
			if (pageNumber && pageNumber > 1) {
				var tid = splitted[3];
				updateBookmark(tid, pageNumber);
			}

			if (!options.collapse_i) {
				$('div.forum-post > blockquote > blockquote').click(function() {
					$(this).toggleClass('collapsable');
				});
			}
		}
		var itemCount = $('.navbar-static-top li.lessons a span').text();
		if (itemCount) {
			if (itemCount != '0') {
				var loadLessons = options.redirect_i;
				if (!loadLessons) {
					if (!localStorage.getItem('lessonsFound')) {
						loadLessons = true;
						localStorage.setItem('lessonsFound', true);
					}
				}
				if (loadLessons) {
					window.location.pathname = '/lesson/session';
					return;
				}
			} else {
				localStorage.setItem('lessonsFound', false);
			}
		}
		if (!options.redirect_i) {
			var nextTimeDisplay = $('.review-status li.next time');
			if (nextTimeDisplay.length > 0) {
				var diff = nextTimeDisplay.attr('datetime') - new Date().getTime() / 1000;
				if (diff > 10) {
					setTimeout(function() {
						window.location.pathname = '/review/session';
					}, Math.ceil(diff * 1000) + 1000);
					return;
				}
			}
		}
	});
}

window.onfocus = function() {
	if (typeof DateTime !== "undefined")
		DateTime.activateFuzzyDate();
};
<commit_msg>Require reviews to be at least 30s in the future before auto-redirecting - works around WK's incorrectly reported next review time<commit_after>if (!window.$) {
	for (var key in window) {
		if (key.substr(0, 6).toLowerCase() == 'jquery') {
			window.$ = window[key].handle;
			break;
		}
	}
}

if (window.$) {
	var options, radData, kanData, prevItem, bookmarks;

	function updateBookmark(thread, page) {
		bookmarks[thread] = page;
		localStorage.setItem('bookmarks', JSON.stringify(bookmarks));
	}

	function levelIndex(item, currRad, currKan) {
		if (item.rad) {
			if (currRad && currRad.indexOf(item.en[0]) !== -1)
				return 0;
		} else if (item.kan) {
			if (currKan && currKan.indexOf(item.kan) !== -1)
				return 1;
		}
		return 2;
	}

	// Lesson/Review queuing
	function setLessonsQueue(needsUpdating) {
		if (options.sort_rad_i)
			return;
		var revArr = $.jStorage.get('l/activeQueue');
		if (!revArr)
			return;
		var storedReviews = $.jStorage.get("l/lessonQueue");
		if (!needsUpdating) {
			for (var i = 0; i < storedReviews.length; ++i) {
				var item = storedReviews[i];
				if (item && item.rad) {
					needsUpdating = true;
					break;
				}
			}
		}
		if (!needsUpdating)
			return;

		var itemsArrays = [[], [], []];
		storedReviews = storedReviews.concat(revArr);
		var currCount = 0;
		for (var i = 0; i < storedReviews.length; ++i) {
			var item = storedReviews[i];
			if (item && item.rad) {
				console.log(item);
				itemsArrays[0].push(item);
				++currCount;
			} else {
				itemsArrays[2].push(item);
			}
		}
		var actQueue = itemsArrays[0].concat(itemsArrays[1]);
		$.jStorage.set('l/activeQueue', actQueue);
		$.jStorage.set('l/lessonQueue', itemsArrays[2]);
	}

	function setReviewQueue(needsUpdating) {
		var currRad = !options.sort_rad_i ? localStorage.getItem('radicalData') : null;
		var currKan = options.sort_kan ? localStorage.getItem('kanjiData') : null;
		var storedReviews = $.jStorage.get("reviewQueue");
		var checkBurn = false; // !options.sort_burn_i; TODO fix
		if (!needsUpdating) {
			for (var i = 0; i < storedReviews.length; ++i) {
				var item = storedReviews[i];
				if (!item)
					continue;
				if ((checkBurn && item.srs == 8) || levelIndex(item, currRad, currKan) !== 2) {
					needsUpdating = true;
					break;
				}
			}
		}
		if (!needsUpdating)
			return;

		var itemsArrays = [[], [], []];
		var revArr = $.jStorage.get('activeQueue');
		if (!revArr)
			return;
		storedReviews = storedReviews.concat(revArr);
		var currCount = 0, burnCount = 0;
		for (var i = 0; i < storedReviews.length; ++i) {
			var item = storedReviews[i];
			if (item) {
				var li;
				if (checkBurn && item.srs == 8) {
					li = 1;
					++burnCount;
				} else {
					li = levelIndex(item, currRad, null);
					if (li < 2)
						++currCount;
				}
				itemsArrays[li].push(item);
			}
		}
		var actQueue = itemsArrays[0].concat(itemsArrays[1]);
		$.jStorage.set('activeQueue', actQueue);
		$.jStorage.set('reviewQueue', itemsArrays[2]);
		$('#question #current-count').text(currCount);
		$('#question #burn-count').text(burnCount);
		$('#question #current-stats').toggle(currCount > 0);
		$('#question #burn-stats').toggle(burnCount > 0);
	}

	function onItemFinished(key, action) {
		if (!prevItem)
			return;
		if (prevItem.srs == 8) {
			var currText = $('#question #burn-count');
			var currValue = parseInt(currText.text());
			if (currValue > 1) {
				currText.text(currValue - 1);
			} else {
				$('#question #burn-stats').hide();
			}
		} else {
			var lIdx = levelIndex(prevItem, radData, kanData);
			if (lIdx < 2) {
				var currText = $('#question #current-count');
				var currValue = parseInt(currText.text());
				if (currValue > 1) {
					currText.text(currValue - 1);
				} else {
					$('#question #current-stats').hide();
				}
			}
		}
	}

	if ($.jStorage && $('#lessons').length == 0) {
		var kunyomi_list = [
			"売","草","戸","糸","皿","竹","皮","花","耳","又","雪","打","村","貝","赤","夏","兄","広","父","冬","久","谷","川","田","目","夕","付","左","手","合","四","犬","引","玉","申","々","投","雲","森","朝","紙","首","何","雨","色","里","羽","池","黄","星","麦","母","丸","見","右","虫","石","林","氷","考","飲","泳","顔","軽","葉","頭","起","読","横","追","島","待","受","指","拾","伝","仲","寒","湯","歯","昔","始","持","乗","物","良","声","方","鳴","答","橋","緑","鏡","様","悲","祭","暑","着","皆","場","買","泣","猫","秋","帰","晴","昼","春","浅","寺","岩","坂","浜","芽","甘","替","奪","磨","貸","埼","滝","翔","懐","遠","遊","荒","俺","鼻","塩","熊","戻","梅","箱","荷","喜","笑","取","浴","若","舌","胸","忙","困","底","臭","穴","岡","尻","浮","焼","株","渡","宮","違","狭","届","腰","肩","値","割","傘","側","呼","抜","針","掛","城","細","厚","藤","靴","娘","江","詰","渇","押","枕","悩","酢","縦","幾","亀","彼","卵","飼","込","机","窓","灰","汗","杉","爪","裏","巣","捨","鍋","払","埋","吐","芋","恥","豚","緩","寝","抱","繰","伸","津","幅","沖","扱","宜","控","壁","片","稲","駆","吹","堀","桃","瀬","蛍","虎","蜂","桜","枠","賭","髪","梨","伺","畑","涙","堅","綱","潟","誰","笠","嵐","姫","謎","刃","侍","曇","呪","也","頃","舟","肌","棚","釣","腕","芝","袋","柄","琴","沼","垣","叱",
			"墨","癖","吾","鍵","猿","箸","霧","唇","虹","爽","脇","咲","踊","闇","霜","蚊","貼","蛇","煮","駒","桑","鰐","蟹","淀"
		];
		radData = localStorage.getItem('radicalData');
		kanData = localStorage.getItem('kanjiData');
		$.jStorage.listenKeyChange('lastItems', onItemFinished);
		$('input').attr('autocomplete', 'off');
		$.jStorage.listenKeyChange('currentItem', function(key, action) {
			var item = $.jStorage.get(key);
			if (!item)
				return;
			var burning = item.srs == 8;
		    var lIdx = levelIndex(item, radData, kanData);
			$('.icon-chevron-right').toggleClass('icon-burn burning', burning);
			$('.icon-chevron-right').toggleClass('icon-level active-level', !burning && lIdx !== 2);
			if (lIdx === 0) {
				console.log(item.rad + ': ' + item.en[0]);
			} else if (lIdx === 1) {
				var read = item.emph === 'onyomi' ? item.on : item.kun;
				console.log(item.kan + ': ' + item.en[0] + '  ' + read);
			}

			var kChar = item.kan;
			if (kChar) {
				setTimeout(function() {
					var quest = $('#question-type.reading');
					if (quest.length !== 0) {
						var found = 'On';
						for (var i = 0; i < kunyomi_list.length; i++) {
						    if (kunyomi_list[i] === kChar) {
						        found = 'Kun';
						        break;
						    }
						}
						quest.html('
' + found + "'yomi Reading?
");
					}
				}, 0);
			}
			prevItem = item;
		});
	}

	// Page load
	$(function() {
		var stored = $('#customizer').html();
		if (stored && stored.length !== 0) {
			options = JSON.parse(stored);
		} else {
			options = {};
		}
		if ($.jStorage) {
			if (document.getElementById('#lessons')) {
				setLessonsQueue(true);
				setTimeout(setLessonsQueue, 2000);
				return;
			}
			if (document.getElementById('#reviews')) {
				setReviewQueue(true);
				setTimeout(function() { setReviewQueue(true); }, 5000);
				setInterval(setReviewQueue, 60000);
				return;
			}
		}
		var revDisplay = $('li.reviews a');
		if (revDisplay && revDisplay.find('span').text() != '0') {
			revDisplay.attr('href', '/review/session');
		}
		revDisplay = $('li.lessons a');
		if (revDisplay && revDisplay.find('span').text() != '0') {
			revDisplay.attr('href', '/lesson/session');
		}

		var splitted = document.location.pathname.split('/');
		var siteSection = splitted[1];
		var isHome = !siteSection || siteSection === 'dashboard';
		if (isHome || siteSection === 'chat') {
			bookmarks = localStorage.getItem('bookmarks');
			if (bookmarks) {
				bookmarks = JSON.parse(bookmarks);
			} else {
				bookmarks = {};
			}
		}
		if (isHome) {
			$('.forum-topics-list table tr td:first-child a:first-child').each(function() {
				var pageUrl = $(this).attr('href');
				var tid = pageUrl.split('/')[3];
				var storedPage = bookmarks[tid];
				if (storedPage)
					$(this).attr('href', pageUrl + '/page/' + storedPage);
			});
			var title = 'radicalData';
			var idx = 0;
			$('.lattice-single-character ul').each(function() {
				var stor = [];
				if (idx === 1) {
					// stor = $(this).find('li').text().split('');
					return;
				} else {
					$(this).find('li').each(function() {
						var iName;
						iName = $(this).find('a').attr('data-original-title');
						stor.push(iName);
					});
				}
				localStorage.setItem(title, stor);
				title = 'kanjiData';
				++idx;
			});
		} else if (siteSection === 'chat') {
			var pageNumber = splitted[5];
			if (pageNumber && pageNumber > 1) {
				var tid = splitted[3];
				updateBookmark(tid, pageNumber);
			}

			if (!options.collapse_i) {
				$('div.forum-post > blockquote > blockquote').click(function() {
					$(this).toggleClass('collapsable');
				});
			}
		}
		var itemCount = $('.navbar-static-top li.lessons a span').text();
		if (itemCount) {
			if (itemCount != '0') {
				var loadLessons = options.redirect_i;
				if (!loadLessons) {
					if (!localStorage.getItem('lessonsFound')) {
						loadLessons = true;
						localStorage.setItem('lessonsFound', true);
					}
				}
				if (loadLessons) {
					window.location.pathname = '/lesson/session';
					return;
				}
			} else {
				localStorage.setItem('lessonsFound', false);
			}
		}
		if (!options.redirect_i) {
			var nextTimeDisplay = $('.review-status li.next time');
			if (nextTimeDisplay.length > 0) {
				var diff = nextTimeDisplay.attr('datetime') - new Date().getTime() / 1000;
				if (diff > 60) {
					setTimeout(function() {
						window.location.pathname = '/review/session';
					}, Math.ceil(diff * 1000) + 1000);
					return;
				}
			}
		}
	});
}

window.onfocus = function() {
	if (typeof DateTime !== "undefined")
		DateTime.activateFuzzyDate();
};
<|endoftext|>


<commit_before>define(function(require) {
    var _ = require('underscore'),
        util = require('util'),
        loader = require('core/loader'),
        Entity = require('core/entity'),
        Bullet = require('bullet'),
        Tileset = require('core/tileset');

    function Player(engine) {
        Entity.call(this, engine);
        return _.extend(this, {
            vy: 0,
            standing: false,
            tileset: new Tileset(loader.get('player'), 16, 16, 0, 0, {}),
            frame: 0,
            tile: 0,
            dir: util.RIGHT,
            bounding_box: {left: 4, top: 0, right: 11, bottom: 15},
            shooting: false,
            has_laser: false
        });
    }

    _.extend(Player.prototype, Entity.prototype, {
        anim: function() {
            if (this.standing) {
                if (this.shooting) {
                    this.tile = 3;
                    this.frame = -8;
                } else if (!this.moving) {
                    this.tile = 0;
                    this.frame = 0;
                } else {
                    this.frame++;
                    if (this.frame > 7) this.frame = 0;
                    if (this.frame >= 0) {
                        if (this.frame < 4) {
                            this.tile = 0;
                        } else {
                            this.tile = 1;
                        }
                    }
                }
            } else {
                this.tile = 2;
            }

            if (this.dir === util.LEFT) {
                this.tile += 4;
            }
        },
        tick: function() {
            var kb = this.engine.kb,
                dx = 0, dy = 0;

            if (kb.keys[kb.RIGHT]) {dx += 1; this.dir = util.RIGHT;}
            if (kb.keys[kb.LEFT]) {dx -= 1; this.dir = util.LEFT;}
            this.moving = dx !== 0;

            this.vy += 0.1;
            if (this.vy > 4) this.vy = 4;

            var xcol = this.engine.collides(this.collision_box(dx, 0)),
                ycol = this.engine.collides(this.collision_box(0, Math.ceil(this.vy)));
            this.standing = (this.vy > 0 && ycol.solid);

            if (this.standing) {
                if (kb.keys[kb.A]) {
                    engine.play("assets/audio/jump.ogg");
                    this.vy = -3;
                } else {
                    this.vy = 0;
                    this.y = ycol.stand - (this.bounding_box.bottom + 1);
                }
            } else if (ycol.solid) {
                this.vy = 0;
            }

            if (kb.pressed(kb.A)) {
                engine.play("assets/audio/jump.ogg");
                this.vy = -3;
            }

            if(kb.pressed(kb.SPACE) || kb.pressed(kb.B)) {
                this.shooting = true;
                var grenade = kb.pressed(kb.SPACE);
                this.engine.add_entity(new Bullet(this.engine,
                                                  this.x + (this.dir == util.LEFT ? 0 : 16),
                                                  this.y + 8,
                                                  4.0,
                                                  this.dir, grenade, this.has_laser));
                if (grenade) {
                    engine.play("assets/audio/grenade.ogg");
                } else {
                    engine.play("assets/audio/shoot.ogg");
                }
            } else {
                this.shooting = false;
            }

            if (!xcol.solid) this.x += dx;
            this.y += this.vy;
        },

        render: function(ctx, x, y) {
            this.anim();
            this.tileset.drawTile(ctx, this.tile, this.x - x, this.y - y);
        },

        collide: function(obj) {
            if(obj.name == 'enemy') {
                this.engine.remove_entity(this);
            }
        },

        collision_box: function(dx, dy) {
            return {
                left: this.x + dx + this.bounding_box.left,
                right: this.x + dx + this.bounding_box.right,
                top: this.y + dy + this.bounding_box.top,
                bottom: this.y + dy + this.bounding_box.bottom
            };
        }
    });

    return Player;
});
<commit_msg>fix double jumps<commit_after>define(function(require) {
    var _ = require('underscore'),
        util = require('util'),
        loader = require('core/loader'),
        Entity = require('core/entity'),
        Bullet = require('bullet'),
        Tileset = require('core/tileset');

    function Player(engine) {
        Entity.call(this, engine);
        return _.extend(this, {
            vy: 0,
            standing: false,
            tileset: new Tileset(loader.get('player'), 16, 16, 0, 0, {}),
            frame: 0,
            tile: 0,
            dir: util.RIGHT,
            bounding_box: {left: 4, top: 0, right: 11, bottom: 15},
            shooting: false,
            has_laser: false,
            num_jumps: 0
        });
    }

    _.extend(Player.prototype, Entity.prototype, {
        anim: function() {
            if (this.standing) {
                if (this.shooting) {
                    this.tile = 3;
                    this.frame = -8;
                } else if (!this.moving) {
                    this.tile = 0;
                    this.frame = 0;
                } else {
                    this.frame++;
                    if (this.frame > 7) this.frame = 0;
                    if (this.frame >= 0) {
                        if (this.frame < 4) {
                            this.tile = 0;
                        } else {
                            this.tile = 1;
                        }
                    }
                }
            } else {
                this.tile = 2;
            }

            if (this.dir === util.LEFT) {
                this.tile += 4;
            }
        },
        tick: function() {
            var kb = this.engine.kb,
                dx = 0, dy = 0;

            if (kb.keys[kb.RIGHT]) {dx += 1; this.dir = util.RIGHT;}
            if (kb.keys[kb.LEFT]) {dx -= 1; this.dir = util.LEFT;}
            this.moving = dx !== 0;

            this.vy += 0.1;
            if (this.vy > 4) this.vy = 4;

            var xcol = this.engine.collides(this.collision_box(dx, 0)),
                ycol = this.engine.collides(this.collision_box(0, Math.ceil(this.vy)));
            this.standing = (this.vy > 0 && ycol.solid);

            if (ycol.solid) {
                this.vy = 0;
                this.y = ycol.stand - (this.bounding_box.bottom + 1);
                this.num_jumps = 0;
            }

            if (kb.pressed(kb.A) && this.num_jumps < 2) {
                engine.play("assets/audio/jump.ogg");
                this.num_jumps++;
                this.vy = -3;
            }

            if(kb.pressed(kb.SPACE) || kb.pressed(kb.B)) {
                this.shooting = true;
                var grenade = kb.pressed(kb.SPACE);
                this.engine.add_entity(new Bullet(this.engine,
                                                  this.x + (this.dir == util.LEFT ? 0 : 16),
                                                  this.y + 8,
                                                  4.0,
                                                  this.dir, grenade, this.has_laser));
                if (grenade) {
                    engine.play("assets/audio/grenade.ogg");
                } else {
                    engine.play("assets/audio/shoot.ogg");
                }
            } else {
                this.shooting = false;
            }

            if (!xcol.solid) this.x += dx;
            this.y += this.vy;
        },

        render: function(ctx, x, y) {
            this.anim();
            this.tileset.drawTile(ctx, this.tile, this.x - x, this.y - y);
        },

        collide: function(obj) {
            if(obj.name == 'enemy') {
                this.engine.remove_entity(this);
            }
        },

        collision_box: function(dx, dy) {
            return {
                left: this.x + dx + this.bounding_box.left,
                right: this.x + dx + this.bounding_box.right,
                top: this.y + dy + this.bounding_box.top,
                bottom: this.y + dy + this.bounding_box.bottom
            };
        }
    });

    return Player;
});
<|endoftext|>


<commit_before>//console.log(testData);

var content=[];

var headingIndex = 0;
for (cellData in testData) {
  document.getElementById("cellNameTemplate").innerText = testData[cellData]["name"];
  document.getElementById("cellImageTemplate").className = ("menu-sprite b"+ cellData);
  document.getElementById("cellNumberTemplate").innerText = testData[cellData]["num"];
  var cellTemplate = document.getElementById("cellTemplate").outerHTML;
  content.push(cellTemplate);

  headingIndex++;
  console.log(headingIndex);
  if (headingIndex >= 30){
    headingIndex = 0;
    content.push(document.getElementById("headingTemplate").outerHTML);
  }
}
content.push(document.getElementById("spacerTemplate").outerHTML);
content = content.join("");
console.log(headingIndex);
document.getElementById('content').innerHTML = content;

<commit_msg>Update script.js<commit_after>//console.log(testData);

var content=[];

var headingIndex = 0;
for (cellData in testData) {
  document.getElementById("cellNameTemplate").innerText = testData[cellData]["name"];
  document.getElementById("cellImageTemplate").className = ("menu-sprite b"+ cellData);
  document.getElementById("cellNumberTemplate").innerText = testData[cellData]["num"];
  var cellTemplate = document.getElementById("cellTemplate").outerHTML;
  content.push(cellTemplate);

  headingIndex++;
  if (headingIndex >= 30){
    headingIndex = 0;
    content.push(document.getElementById("headingTemplate").outerHTML);
  }
}
content.push(document.getElementById("spacerTemplate").outerHTML);
content = content.join("");
document.getElementById('content').innerHTML = content;

<|endoftext|>


<commit_before>/*
 * Author: Ensky Lin(http://www.ensky.tw/)
 * Licence: http://creativecommons.org/licenses/by-nc-sa/3.0/
 */
window.isLogin = false;
    window.fbAsyncInit = function() {
      // init the FB JS SDK
      FB.init({
        appId      : '313564748761564', // App ID from the App Dashboard
        channelUrl : '//ensky.tw/FriendMining/channel.php', // Channel File for x-domain communication
        status     : true, // check the login status upon init?
        cookie     : true, // set sessions cookies to allow your server to access the session?
        xfbml      : true  // parse XFBML tags on this page?
      });
      $('#login-btn').attr('disabled', false);
    };

    // Load the SDK's source Asynchronously
    // Note that the debug version is being actively developed and might
    // contain some type checks that are overly strict.
    // Please report such bugs using the bugs tool.
    (function(d, debug){
       var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
       if (d.getElementById(id)) {return;}
       js = d.createElement('script'); js.id = id; js.async = true;
       js.src = "//connect.facebook.net/en_US/all" + (debug ? "/debug" : "") + ".js";
       ref.parentNode.insertBefore(js, ref);
     }(document, /*debug*/ false));

var EFB = function () {
  var until, since, until_this_round, grab_limit;
  var Data = {
    msgs: {},
    users: {/*name, likes, comments*/},
    ranks: {
      like: PriorityQueue({low: true}),
      comment: PriorityQueue({low: true}),
      all: PriorityQueue({low: true})
    },
    names: [],
    name_id: {}
  };
  var T = {
    'page_user': _.template($('#t-page-user').html()),
    'user': _.template($('#t-user').html()),
    'like': _.template($('#t-like').html()),
    'comment': _.template($('#t-comment').html())
  };
  window.Data = Data;

  var parseCommentLike = function (type, row) {
      var initUser = function (userid, name) {
          if (typeof Data.users[userid] === 'undefined') {
              Data.users[userid] = {
                  name: name,
                  likes: [],
                  comments: {}
              }
              // name remapping
              Data.names.push(name);
              Data.name_id[name] = userid;
              // search autocomplete
              $('#search-input').autocomplete({
                  source: Data.names
              });
          }
      };

      // since判斷
      var filterCreateTime = function (created_time) {
          var ct = (new Date(created_time)) / 1000;
          if (ct >= since) {
              if (ct < until_this_round)
                  until_this_round = ct;
              return true;
          } else {
              return false;
          }
      };
      var msg_id = row.id;
      Data.msgs[msg_id] = Data.msgs[msg_id] || {
          picture: row.picture || '',
          link: row.link || '',
          message: row.message || '',
          created_time: new Date(row.created_time)
      };

      if ( filterCreateTime(row.created_time) ) {
        datas = type == 'comment' ? row.comments.data : row.likes.data;
        rankobj = Data.ranks;
        $.each(datas, function (index, d) {
            var user_id;
            if ( type == 'comment' ) {
                user_id = d.from.id;
                if (user_id != FBID) {
                  initUser(user_id, d.from.name);
                  userobj = Data.users[user_id];
                  userobj['comments'][msg_id] = d.message;
                  rankobj.comment.remove(user_id);
                  rankobj.comment.push(user_id, Object.keys(userobj['comments']).length);
                }
            } else {
                user_id = d.id;
                if (user_id != FBID) {
                  initUser(user_id, d.name);
                  userobj = Data.users[user_id];
                  userobj['likes'].push(msg_id);
                  rankobj.like.remove(user_id);
                  rankobj.like.push(user_id, Object.keys(userobj['likes']).length);
                }
            }

            if (user_id != FBID) {
              rankobj.all.remove(user_id);
              rankobj.all.push(user_id, Object.keys(userobj['comments']).length + Object.keys(userobj['likes']).length);
            }
        });
      }
  }

  var joinData = function (datas) {
      $.each(datas, function (index, d) {
          if (typeof d.comments == "object" && d.comments.count != 0) {
              parseCommentLike("comment", d);
          }
          if (typeof d.likes == "object" && d.likes.count != 0) {
              parseCommentLike("like", d);
          }
      });
  }

  var init = function (form_since) {
      until = Math.floor(new Date().getTime() / 1000);
      since = new Date();
      switch (form_since) {
        case "week":
          since.setTime( since.getTime() - 60*60*24*7 * 1000 );
          grab_limit = 30;
          break;
        case "month":
          since.setDate(1);
          grab_limit = 50;
          break;
        case "year":
          since.setFullYear(since.getFullYear() - 1);
          grab_limit = 80;
          break;
        case "forever":
          since = null;
          grab_limit = 100;
          break;
      }
      until_this_round = (new Date().getTime()) / 1000;
      if ( since ) {
        since = Math.floor(since.getTime() / 1000);
      }
      // search
      $('#search-form').submit(function () {
          event.preventDefault();
          var query = $('#search-input').val();
          if ( typeof Data.name_id[query] !== 'undefined') {
              window.Router.navigate("#/user/" + Data.name_id[query], {trigger: true});
              $('#search-input').val('');
          }
          return false;
      });
      call();
  }

  var render_user = function (id) {
    if ( typeof Data.users[id] === 'object' ) {
        var prepare = function (type) {
            var result = {
              msgs: Data.msgs
            };
            result.datas = Data.users[id][type];
            result.getLink = function (msg_id) {
                if (Data.msgs[msg_id].message == '' && Data.msgs[msg_id].link != '') {
                    return Data.msgs[msg_id].link;
                } else {
                    return 'http://www.facebook.com/' + msg_id;
                }
            };
            return result;
        }
        $("#page-user").html(T.page_user({id: id, name: Data.users[id].name}));
        $("#user-like").html(T.like(prepare('likes')));
        $("#user-comment").html(T.comment(prepare('comments')));
    }
  };

  var render = function () {
      var parse_result = function (results) {
          var r = [];
          _.each(results, function (result) {
              r.push({
                  id: result.object,
                  name: Data.users[result.object].name,
                  count: result.priority
              });
          });
          return r;
      };
      $("#main-like").html(T.user({users: parse_result(Data.ranks.like.result())}));
      $("#main-comment").html(T.user({users: parse_result(Data.ranks.comment.result())}));
      $("#main-all").html(T.user({users: parse_result(Data.ranks.all.result())}));
  };

  var loadingCount = 0,
      stop_loading = 0;

  $('#stop-loading').click(function () {
      stop_loading = 1;
  });
  var call = function () {
    $('#loading-gif').show();
    loadingCount++;
    FB.api('/me/posts?fields=message,likes,comments,link,picture&limit='+ grab_limit +'&until=' + until, function(d) {
        if (typeof d.paging.next !== 'undefined') {
            until = d.paging.next.match(/until=(\d+)/)[1];
            if ( (!since || until > since) && !stop_loading) {
                call();
            }
        }
        joinData(d.data);
        render();

        $('#loading-date-wrapper').show();
        untilDate = new Date(until_this_round * 1000);
        untilDateString = untilDate.getFullYear() + "/" + (untilDate.getMonth()+1) + "/" + untilDate.getDate();
        $('#loading-date').text(untilDateString);
        loadingCount--;

        if (loadingCount == 0) {
          $('#loading-gif').hide();
        }
    });
  }

  return {
    init: init,
    render: render,
    render_user: render_user
  }
} ();

var WorkspaceRouter = Backbone.Router.extend({

  routes: {
    "" : "index",
    "main": "main",
    "user/:id":   "user",
    "help": "help"
  },

  main: function () {
    $(".page").hide();
    if (isLogin) {
      EFB.render();
      $('#page-main').show();
    } else {
      $("#page-index").show();
      window.Router.navigate("");
    }
  },

  user: function(id) {
    $(".page").hide();
    if (isLogin) {
      EFB.render_user(id);
      $("#page-user").show();
    } else {
      $("#page-index").show();
      window.Router.navigate("");
    }
  },

  help: function () {
      $(".page").hide();
      $('#page-help').show();
  }

});
window.Router = new WorkspaceRouter;
Backbone.history.start();

$('#init-form').submit(function () {
  event.preventDefault();
  var since = $(this).find('input[name="since"]:checked').val();
  FB.login(function(response) {
   if (response.authResponse) {
      FB.api('/me?fields=id', function (d) {
          window.FBID = d.id;
      });

      window.isLogin = true;
      EFB.init(since);
      window.Router.navigate("#/main");
      $('#search-form').show();
   } else {
      console.log('User cancelled login or did not fully authorize.');
   }
  }, {scope: 'read_stream'});
  return false;
});<commit_msg>event<commit_after>/*
 * Author: Ensky Lin(http://www.ensky.tw/)
 * Licence: http://creativecommons.org/licenses/by-nc-sa/3.0/
 */
window.isLogin = false;
    window.fbAsyncInit = function() {
      // init the FB JS SDK
      FB.init({
        appId      : '313564748761564', // App ID from the App Dashboard
        channelUrl : '//ensky.tw/FriendMining/channel.php', // Channel File for x-domain communication
        status     : true, // check the login status upon init?
        cookie     : true, // set sessions cookies to allow your server to access the session?
        xfbml      : true  // parse XFBML tags on this page?
      });
      $('#login-btn').attr('disabled', false);
    };

    // Load the SDK's source Asynchronously
    // Note that the debug version is being actively developed and might
    // contain some type checks that are overly strict.
    // Please report such bugs using the bugs tool.
    (function(d, debug){
       var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
       if (d.getElementById(id)) {return;}
       js = d.createElement('script'); js.id = id; js.async = true;
       js.src = "//connect.facebook.net/en_US/all" + (debug ? "/debug" : "") + ".js";
       ref.parentNode.insertBefore(js, ref);
     }(document, /*debug*/ false));

var EFB = function () {
  var until, since, until_this_round, grab_limit;
  var Data = {
    msgs: {},
    users: {/*name, likes, comments*/},
    ranks: {
      like: PriorityQueue({low: true}),
      comment: PriorityQueue({low: true}),
      all: PriorityQueue({low: true})
    },
    names: [],
    name_id: {}
  };
  var T = {
    'page_user': _.template($('#t-page-user').html()),
    'user': _.template($('#t-user').html()),
    'like': _.template($('#t-like').html()),
    'comment': _.template($('#t-comment').html())
  };
  window.Data = Data;

  var parseCommentLike = function (type, row) {
      var initUser = function (userid, name) {
          if (typeof Data.users[userid] === 'undefined') {
              Data.users[userid] = {
                  name: name,
                  likes: [],
                  comments: {}
              }
              // name remapping
              Data.names.push(name);
              Data.name_id[name] = userid;
              // search autocomplete
              $('#search-input').autocomplete({
                  source: Data.names
              });
          }
      };

      // since判斷
      var filterCreateTime = function (created_time) {
          var ct = (new Date(created_time)) / 1000;
          if (ct >= since) {
              if (ct < until_this_round)
                  until_this_round = ct;
              return true;
          } else {
              return false;
          }
      };
      var msg_id = row.id;
      Data.msgs[msg_id] = Data.msgs[msg_id] || {
          picture: row.picture || '',
          link: row.link || '',
          message: row.message || '',
          created_time: new Date(row.created_time)
      };

      if ( filterCreateTime(row.created_time) ) {
        datas = type == 'comment' ? row.comments.data : row.likes.data;
        rankobj = Data.ranks;
        $.each(datas, function (index, d) {
            var user_id;
            if ( type == 'comment' ) {
                user_id = d.from.id;
                if (user_id != FBID) {
                  initUser(user_id, d.from.name);
                  userobj = Data.users[user_id];
                  userobj['comments'][msg_id] = d.message;
                  rankobj.comment.remove(user_id);
                  rankobj.comment.push(user_id, Object.keys(userobj['comments']).length);
                }
            } else {
                user_id = d.id;
                if (user_id != FBID) {
                  initUser(user_id, d.name);
                  userobj = Data.users[user_id];
                  userobj['likes'].push(msg_id);
                  rankobj.like.remove(user_id);
                  rankobj.like.push(user_id, Object.keys(userobj['likes']).length);
                }
            }

            if (user_id != FBID) {
              rankobj.all.remove(user_id);
              rankobj.all.push(user_id, Object.keys(userobj['comments']).length + Object.keys(userobj['likes']).length);
            }
        });
      }
  }

  var joinData = function (datas) {
      $.each(datas, function (index, d) {
          if (typeof d.comments == "object" && d.comments.count != 0) {
              parseCommentLike("comment", d);
          }
          if (typeof d.likes == "object" && d.likes.count != 0) {
              parseCommentLike("like", d);
          }
      });
  }

  var init = function (form_since) {
      until = Math.floor(new Date().getTime() / 1000);
      since = new Date();
      switch (form_since) {
        case "week":
          since.setTime( since.getTime() - 60*60*24*7 * 1000 );
          grab_limit = 30;
          break;
        case "month":
          since.setDate(1);
          grab_limit = 50;
          break;
        case "year":
          since.setFullYear(since.getFullYear() - 1);
          grab_limit = 80;
          break;
        case "forever":
          since = null;
          grab_limit = 100;
          break;
      }
      until_this_round = (new Date().getTime()) / 1000;
      if ( since ) {
        since = Math.floor(since.getTime() / 1000);
      }
      // search
      $('#search-form').submit(function () {
          // event.preventDefault();
          var query = $('#search-input').val();
          if ( typeof Data.name_id[query] !== 'undefined') {
              window.Router.navigate("#/user/" + Data.name_id[query], {trigger: true});
              $('#search-input').val('');
          }
          return false;
      });
      call();
  }

  var render_user = function (id) {
    if ( typeof Data.users[id] === 'object' ) {
        var prepare = function (type) {
            var result = {
              msgs: Data.msgs
            };
            result.datas = Data.users[id][type];
            result.getLink = function (msg_id) {
                if (Data.msgs[msg_id].message == '' && Data.msgs[msg_id].link != '') {
                    return Data.msgs[msg_id].link;
                } else {
                    return 'http://www.facebook.com/' + msg_id;
                }
            };
            return result;
        }
        $("#page-user").html(T.page_user({id: id, name: Data.users[id].name}));
        $("#user-like").html(T.like(prepare('likes')));
        $("#user-comment").html(T.comment(prepare('comments')));
    }
  };

  var render = function () {
      var parse_result = function (results) {
          var r = [];
          _.each(results, function (result) {
              r.push({
                  id: result.object,
                  name: Data.users[result.object].name,
                  count: result.priority
              });
          });
          return r;
      };
      $("#main-like").html(T.user({users: parse_result(Data.ranks.like.result())}));
      $("#main-comment").html(T.user({users: parse_result(Data.ranks.comment.result())}));
      $("#main-all").html(T.user({users: parse_result(Data.ranks.all.result())}));
  };

  var loadingCount = 0,
      stop_loading = 0;

  $('#stop-loading').click(function () {
      stop_loading = 1;
  });
  var call = function () {
    $('#loading-gif').show();
    loadingCount++;
    FB.api('/me/posts?fields=message,likes,comments,link,picture&limit='+ grab_limit +'&until=' + until, function(d) {
        if (typeof d.paging.next !== 'undefined') {
            until = d.paging.next.match(/until=(\d+)/)[1];
            if ( (!since || until > since) && !stop_loading) {
                call();
            }
        }
        joinData(d.data);
        render();

        $('#loading-date-wrapper').show();
        untilDate = new Date(until_this_round * 1000);
        untilDateString = untilDate.getFullYear() + "/" + (untilDate.getMonth()+1) + "/" + untilDate.getDate();
        $('#loading-date').text(untilDateString);
        loadingCount--;

        if (loadingCount == 0) {
          $('#loading-gif').hide();
        }
    });
  }

  return {
    init: init,
    render: render,
    render_user: render_user
  }
} ();

var WorkspaceRouter = Backbone.Router.extend({

  routes: {
    "" : "index",
    "main": "main",
    "user/:id":   "user",
    "help": "help"
  },

  main: function () {
    $(".page").hide();
    if (isLogin) {
      EFB.render();
      $('#page-main').show();
    } else {
      $("#page-index").show();
      window.Router.navigate("");
    }
  },

  user: function(id) {
    $(".page").hide();
    if (isLogin) {
      EFB.render_user(id);
      $("#page-user").show();
    } else {
      $("#page-index").show();
      window.Router.navigate("");
    }
  },

  help: function () {
      $(".page").hide();
      $('#page-help').show();
  }

});
window.Router = new WorkspaceRouter;
Backbone.history.start();

$('#init-form').submit(function () {
  // event.preventDefault();
  var since = $(this).find('input[name="since"]:checked').val();
  FB.login(function(response) {
   if (response.authResponse) {
      FB.api('/me?fields=id', function (d) {
          window.FBID = d.id;
      });

      window.isLogin = true;
      EFB.init(since);
      window.Router.navigate("#/main");
      $('#search-form').show();
   } else {
      console.log('User cancelled login or did not fully authorize.');
   }
  }, {scope: 'read_stream'});
  return false;
});<|endoftext|>


<commit_before>/*
 * Created 2014 Triangle717
 * <http://Triangle717.WordPress.com/>
 *
 * Licensed under The MIT License
 * <http://opensource.org/licenses/MIT/>
 */

(function() {
  "use strict";
  /* Display the site sidebar button */

  $(window).resize(function() {
    if (($(window).width() >= 320 || $(window).width() <= 320) && $(window).width() <= 720) {
      $("#sidebar-btn").addClass("sidebar-btn-visible");
      $("#sidebar").addClass("sidebar-hidden");

    } else {
      $("#sidebar-btn").removeClass("sidebar-btn-visible");
      $("#sidebar").removeClass("sidebar-hidden");
    }
  });
})();

function shrinkImages() {
  "use strict";
  /* Resize images on mobile devices */

  $("body").find("img").each(function() {
    var $this = $(this);

    // If this is a mobile browser, scale down non-exempt image sizes
    if ($.browser.mobile || $.browser.desktop) {
      if (!$this.hasClass("no-mobile-resize") && !$this.hasClass("emoji")) {

        // However, do it only if the image is wider than the screen
        console.log("Image width: " + $this.width());
        console.log("Image src: " + $this.attr("src"));
        console.log("Window Width: " + $(window).width());
        console.log("Calculation: " + $(window).width() % $this.width() >= 100);

        if ($(window).width() % $this.width() >= 100) {
          $this.width(this.width() - ($(window).width() % $this.width()));
          $this.height(this.height() - ($(window).height() % $this.height()));
        }
      }
    }
  });
}

$(function() {
  "use strict";

  shrinkImages();

  // Replace the SVG with a PNG on IE (IE HATES SVGs)
  if ($.browser.msie) {
    var $imgSrc = $(".ie-svg").attr("src");
    $(".ie-svg").attr("src", $imgSrc.substring(0, $imgSrc.length - 3) + "png");
  }

  // Hide non-mobile-ready elements
  if ($.browser.mobile) {
    $(".no-mobile").css("display", "none");
  }

  // Fully center the items that need centering
  var $centered = $(".fully-centered");
  $centered.css("margin-left", -$centered.width() / 2);
  $centered.css("margin-top", -$centered.height() / 2);

//  // Get date of last commit using GitHub Pages API
//  $.getJSON("https://api.github.com/repos/le717/le717.github.io", function(data) {
//      var lastUpdate = data.updated_at.replace(/(T(.*))$/g, "");
//      //var lastUpdate = "Right now";
//      $("#last-update").text("Last update: {0}".format(lastUpdate));
//    });
});
<commit_msg>[ci skip]<commit_after>/*
 * Created 2014 Triangle717
 * <http://Triangle717.WordPress.com/>
 *
 * Licensed under The MIT License
 * <http://opensource.org/licenses/MIT/>
 */

(function() {
  "use strict";
  /* Display the site sidebar button */

  $(window).resize(function() {
    if (($(window).width() >= 320 || $(window).width() <= 320) && $(window).width() <= 720) {
      $("#sidebar-btn").addClass("sidebar-btn-visible");
      $("#sidebar").addClass("sidebar-hidden");

    } else {
      $("#sidebar-btn").removeClass("sidebar-btn-visible");
      $("#sidebar").removeClass("sidebar-hidden");
    }
  });
})();

function shrinkImages() {
  "use strict";
  /* Resize images on mobile devices */

  $("body").find("img").each(function() {
    var $this = $(this);

    // If this is a mobile browser, scale down non-exempt image sizes
    if ($.browser.mobile || $.browser.desktop) {
      if (!$this.hasClass("no-mobile-resize") && !$this.hasClass("emoji")) {

        // However, do it only if the image is wider than the screen
        console.log("Image width: " + $this.width());
        console.log("Image src: " + $this.attr("src"));
        console.log("Window Width: " + $(window).width());
        console.log($(window).width() % $this.width() >= 100);

        if ($(window).width() % $this.width() >= 100) {
          $this.width(this.width() - ($(window).width() % $this.width()));
          $this.height(this.height() - ($(window).height() % $this.height()));
        }
      }
    }
  });
}

$(function() {
  "use strict";

  shrinkImages();

  // Replace the SVG with a PNG on IE (IE HATES SVGs)
  if ($.browser.msie) {
    var $imgSrc = $(".ie-svg").attr("src");
    $(".ie-svg").attr("src", $imgSrc.substring(0, $imgSrc.length - 3) + "png");
  }

  // Hide non-mobile-ready elements
  if ($.browser.mobile) {
    $(".no-mobile").css("display", "none");
  }

  // Fully center the items that need centering
  var $centered = $(".fully-centered");
  $centered.css("margin-left", -$centered.width() / 2);
  $centered.css("margin-top", -$centered.height() / 2);

//  // Get date of last commit using GitHub Pages API
//  $.getJSON("https://api.github.com/repos/le717/le717.github.io", function(data) {
//      var lastUpdate = data.updated_at.replace(/(T(.*))$/g, "");
//      //var lastUpdate = "Right now";
//      $("#last-update").text("Last update: {0}".format(lastUpdate));
//    });
});
<|endoftext|>


<commit_before>$(document).ready(function(){

	changeBackground();
	updateClock();

	$('#search input').keypress(function(e) {
		if(e.which == 13) {
			e.preventDefault();
			top.location = 'https://www.google.com/search?q='+$(this).val();
		}
	});

	$('#weather, #miniweather').on('click', function(e){
		$('#weather, #miniweather').toggle();
	});

	getWeather();
});

function changeBackground() {
	$('#background').css('background-image', 'url("https://source.unsplash.com/1920x1080")').waitForImages(function() {
		$('#background').addClass('show');
	}, $.noop, true);
}

function updateClock() {
    var now = new Date(); // current date
	time = ("0" + now.getHours()).slice(-2) + ':' + ("0" + now.getMinutes()).slice(-2) + ':' + ("0" + now.getSeconds()).slice(-2);

    // set the content of the element with the ID time to the formatted string
    $('#clock h1').html(time);

    // call this function again in 1000ms
    setTimeout(updateClock, 1000);
}

function getLocation(callback) {
	if (navigator.geolocation) {
		navigator.geolocation.getCurrentPosition(function(position){
			callback(position.coords);
		});
	} else {
		console.info( "Geolocation is not supported by this browser.");
	}
}

function getWeather() {
	var path = "https://api.openweathermap.org/data/2.5/weather?appid=45dc870e41c6c3980d4d1e446bf6d079&units=metric&lang=es";

	getLocation(function(pos){
		var url = path + "&lat=" + pos.latitude + "&lon=" + pos.longitude;

		$.get({
			url: url,
		}).done(function(response){
			$('#location').text(response.name);
			$('#tempnow').text(normalizeTemp(response.main.temp));
			$('#others').text(normalizeTemp(response.main.temp_min)+' / '+normalizeTemp(response.main.temp_max));
			$('#iWeather').addClass(getWeatherIcon(response.weather[0].id));

			$('#miniiWeather').addClass(getWeatherIcon(response.weather[0].id));
			$('#minitemp').text(normalizeTemp(response.main.temp));

			$('#miniweather').show();
		});
	});
}

function normalizeTemp(temp) {
	return Math.round(temp * 10)/10 + "º";
}

function getWeatherIcon(id) {

	var icons = [];

	//https://openweathermap.org/weather-conditions
	//https://erikflowers.github.io/weather-icons/

	icons[200] = "wi-day-thunderstorm";
	icons[800] = "wi-day-sunny";

	if(icons[id] == undefined) {
		return "wi-alien";
	}
	return icons[id];
}
<commit_msg>change category<commit_after>$(document).ready(function(){

	changeBackground();
	updateClock();

	$('#search input').keypress(function(e) {
		if(e.which == 13) {
			e.preventDefault();
			top.location = 'https://www.google.com/search?q='+$(this).val();
		}
	});

	$('#weather, #miniweather').on('click', function(e){
		$('#weather, #miniweather').toggle();
	});

	getWeather();
});

function changeBackground() {
	$('#background').css('background-image', 'url("https://source.unsplash.com/category/nature/1920x1080")').waitForImages(function() {
		$('#background').addClass('show');
	}, $.noop, true);
}

function updateClock() {
    var now = new Date(); // current date
	time = ("0" + now.getHours()).slice(-2) + ':' + ("0" + now.getMinutes()).slice(-2) + ':' + ("0" + now.getSeconds()).slice(-2);

    // set the content of the element with the ID time to the formatted string
    $('#clock h1').html(time);

    // call this function again in 1000ms
    setTimeout(updateClock, 1000);
}

function getLocation(callback) {
	if (navigator.geolocation) {
		navigator.geolocation.getCurrentPosition(function(position){
			callback(position.coords);
		});
	} else {
		console.info( "Geolocation is not supported by this browser.");
	}
}

function getWeather() {
	var path = "https://api.openweathermap.org/data/2.5/weather?appid=45dc870e41c6c3980d4d1e446bf6d079&units=metric&lang=es";

	getLocation(function(pos){
		var url = path + "&lat=" + pos.latitude + "&lon=" + pos.longitude;

		$.get({
			url: url,
		}).done(function(response){
			$('#location').text(response.name);
			$('#tempnow').text(normalizeTemp(response.main.temp));
			$('#others').text(normalizeTemp(response.main.temp_min)+' / '+normalizeTemp(response.main.temp_max));
			$('#iWeather').addClass(getWeatherIcon(response.weather[0].id));

			$('#miniiWeather').addClass(getWeatherIcon(response.weather[0].id));
			$('#minitemp').text(normalizeTemp(response.main.temp));

			$('#miniweather').show();
		});
	});
}

function normalizeTemp(temp) {
	return Math.round(temp * 10)/10 + "º";
}

function getWeatherIcon(id) {

	var icons = [];

	//https://openweathermap.org/weather-conditions
	//https://erikflowers.github.io/weather-icons/

	icons[200] = "wi-day-thunderstorm";
	icons[800] = "wi-day-sunny";

	if(icons[id] == undefined) {
		return "wi-alien";
	}
	return icons[id];
}
<|endoftext|>


<commit_before>(function($) {

  var storage;

  var Storage = function(id) {
    // Storage for the ordering of the M2M widgets
    // happens in a hidden <textarea> containing a
    // JSON dump with every widget's ordering.

    var element;
    var store = {};

    var _read = function() {
      var text = element.text();
      if (text) {
        store = JSON.parse(element.text());
      }
    };

    var _write = function() {
      element.text(JSON.stringify(store));
    };

    var _get = function(field) {
      return store[field];
    };

    var _set = function(field, content) {
      store[field] = content;
      _write();
      return content;
    };

    var __init = function(id) {
      element = $('#' + id);
      _read();
    };

    __init(id);

    return {
      set: _set,
      get: _get
    };
  };

  var OrderedM2M = function(obj) {
    // Controller to track changes to the ordering and
    // keep the storage updated

    var parent;
    var container;
    var select;
    var controls;
    var add;
    var remove;
    var up;
    var down;
    var id = obj.id;
    var field = obj.field;

    var insertUI = function() {
      controls = $('
');
      up = $('Up');
      down = $('Down');
      controls.append(up, down);
      container.append(controls);
    };

    var getOptions = function() {
      return select.find('option');
    };

    var getSelectedOptions = function() {
      return getOptions().filter(':selected');
    };

    var moveUp = function() {
      if (!up.hasClass('active')) {
        return;
      }
      getSelectedOptions().each(function() {
        var element = $(this);
        var prevElement = element.prev();
        if (prevElement.length) {
          element.insertBefore(prevElement);
        }
      });
      saveOrder();
    };

    var moveDown = function() {
      if (!down.hasClass('active')) {
        return;
      }
      getSelectedOptions().each(function() {
        var element = $(this);
        var nextElement = element.next();
        if (nextElement.length) {
          element.insertAfter(nextElement);
        }
      });
      saveOrder();
    };

    var getOrderedIDs = function() {
      var ids = [];
      var options = getOptions();
      for (var i=0; i<options.length; i++) {
        var val = $(options[i]).val();
        val = parseInt(val);
        ids.push(val);
      }
      return ids;
    };

    var orderOptions = function(orderedIDs) {
      var orderedOptions = [];
      var options = getOptions();
      var option;
      var i;
      for (i=0; i<orderedIDs.length; i++) {
        var id = orderedIDs[i];
        option = options.filter('[value="' + id + '"]');
        orderedOptions.push(option);
        option.detach();
      }
      for (i=0; i<orderedOptions.length; i++) {
        option = orderedOptions[i];
        select.append(option);
      }
    };

    var saveOrder = function() {
      storage.set(field, getOrderedIDs());
    };

    var setInitialOrder = function() {
      var orderedIDs = storage.get(field);
      if (orderedIDs !== undefined) {
        orderOptions(orderedIDs);
      }
    };

    var checkButtons = function() {
      var buttons = up.add(down);
      if (!getSelectedOptions().length) {
        buttons.removeClass('active');
      } else {
        buttons.addClass('active');
      }
    };

    var setBindings = function() {
      up.on('click', moveUp);
      down.on('click', moveDown);
      add.on('click', saveOrder);
      remove.on('click', saveOrder);
      select.on('change', checkButtons);
    };

    var init = function() {
      parent = $('.selector').has('#' + id);
      container = parent.find('.selector-chosen');
      select = container.find('select');
      add = parent.find('.selector-add');
      remove = parent.find('.selector-remove');

      insertUI();
      setBindings();
      setInitialOrder();
    };

    init();
  };

  var init = function() {
    // Store the ordering in a hidden field
    var storageID = orderedFilteredSelectMultiple.storageID;
    storage = Storage(storageID);

    // Bind each of the handlers
    var targets = orderedFilteredSelectMultiple.targets;
    targets.forEach(OrderedM2M);
  };

  $(function() {
    // Delay to allow the Filtered Select widget to be built
    setTimeout(init, 1000);
  });

})(jQuery);

<commit_msg>Updating the widget.<commit_after>(function($) {

  var storage;

  var Storage = function(id) {
    // Storage for the ordering of the M2M widgets
    // happens in a hidden <textarea> containing a
    // JSON dump with every widget's ordering.

    var element;
    var store = {};

    var _read = function() {
      var text = element.text();
      if (text) {
        store = JSON.parse(element.text());
      }
    };

    var _write = function() {
      element.text(JSON.stringify(store));
    };

    var _get = function(field) {
      return store[field];
    };

    var _set = function(field, content) {
      store[field] = content;
      _write();
      return content;
    };

    var __init = function(id) {
      element = $('#' + id);
      _read();
    };

    __init(id);

    return {
      set: _set,
      get: _get
    };
  };

  var OrderedM2M = function(obj) {
    // Controller to track changes to the ordering and
    // keep the storage updated

    var parent;
    var container;
    var select;
    var controls;
    var add;
    var remove;
    var up;
    var down;
    var chooseAll;
    var removeAll;
    var id = obj.id;
    var field = obj.field;

    var insertUI = function() {
      controls = $('
');
      up = $('Up');
      down = $('Down');
      controls.append(up, down);
      container.append(controls);
    };

    var getOptions = function() {
      return select.find('option');
    };

    var getSelectedOptions = function() {
      return getOptions().filter(':selected');
    };

    var moveUp = function() {
      if (!up.hasClass('active')) {
        return;
      }
      getSelectedOptions().each(function() {
        var element = $(this);
        var prevElement = element.prev();
        if (prevElement.length) {
          element.insertBefore(prevElement);
        }
      });
      saveOrder();
    };

    var moveDown = function() {
      if (!down.hasClass('active')) {
        return;
      }
      getSelectedOptions().each(function() {
        var element = $(this);
        var nextElement = element.next();
        if (nextElement.length) {
          element.insertAfter(nextElement);
        }
      });
      saveOrder();
    };

    var getOrderedIDs = function() {
      var ids = [];
      var options = getOptions();
      for (var i=0; i<options.length; i++) {
        var val = $(options[i]).val();
        val = parseInt(val);
        ids.push(val);
      }
      return ids;
    };

    var orderOptions = function(orderedIDs) {
      var orderedOptions = [];
      var options = getOptions();
      var option;
      var i;
      for (i=0; i<orderedIDs.length; i++) {
        var id = orderedIDs[i];
        option = options.filter('[value="' + id + '"]');
        orderedOptions.push(option);
        option.detach();
      }
      for (i=0; i<orderedOptions.length; i++) {
        option = orderedOptions[i];
        select.append(option);
      }
    };

    var saveOrder = function() {
      storage.set(field, getOrderedIDs());
    };

    var setInitialOrder = function() {
      var orderedIDs = storage.get(field);
      if (orderedIDs !== undefined) {
        orderOptions(orderedIDs);
      }
    };

    var checkButtons = function() {
      var buttons = up.add(down);
      if (!getSelectedOptions().length) {
        buttons.removeClass('active');
      } else {
        buttons.addClass('active');
      }
    };

    var setBindings = function() {
      // Ordering UI
      up.on('click', moveUp);
      down.on('click', moveDown);

      // Update the `active` state of the ordering buttons
      select.on('change', checkButtons);

      // Update when the filtered-m2m buttons are clicked
      add.on('click', saveOrder);
      remove.on('click', saveOrder);
      chooseAll.on('click', saveOrder);
      removeAll.on('click', saveOrder);
    };

    var init = function() {
      parent = $('.selector').has('#' + id);
      container = parent.find('.selector-chosen');
      select = container.find('select');
      add = parent.find('.selector-add');
      remove = parent.find('.selector-remove');
      chooseAll = parent.find('.selector-chooseall');
      removeAll = parent.find('.selector-clearall');

      insertUI();
      setBindings();
      setInitialOrder();
    };

    init();
  };

  var init = function() {
    // Store the ordering in a hidden field
    var storageID = orderedFilteredSelectMultiple.storageID;
    storage = Storage(storageID);

    // Bind each of the handlers
    var targets = orderedFilteredSelectMultiple.targets;
    targets.forEach(OrderedM2M);
  };

  $(function() {
    // Delay to allow the Filtered Select widget to be built
    setTimeout(init, 1000);
  });

})(jQuery);

<|endoftext|>


<commit_before><commit_msg>Replace "" with '' in script.js<commit_after><|endoftext|>


<commit_before>var querystring = require('querystring');
var url = require('url');
var MediaType = require('api-media-type');
var querytopic = require('../query_topic');
var streams = require('zetta-streams');
var ObjectStream = streams.ObjectStream;

var ServerResource = module.exports = function(server) {
  this.server = server;
  this.httpScout = this.server.httpScout;
  this.deviceTypes = [];
  this.typeIndex = [];
  this._listeners = {};
};

ServerResource.prototype.getServer = function(env) {
  var parsed = url.parse(env.request.url);
  var re = /^\/servers\/([^\/]+)/;
  var match = re.exec(parsed.pathname);

  var serverId = match && match[1] ? match[1] : this.server.id;

  return { path: '/servers/' + encodeURI(serverId) };
};

ServerResource.prototype.init = function(config) {
  config
    .path('/servers')
    .produces(MediaType.SIREN)
    .consumes(MediaType.FORM_URLENCODED)
    .consumes(MediaType.MULTIPART_FORM_DATA)
    .consumes(MediaType.JSON)
    .get('/{serverId}', this.showServer)
    .get('/{serverId}/devices/{deviceId}', this.showDevice)
    .put('/{serverId}/devices/{deviceId}', this.updateDevice)
    .del('/{serverId}/devices/{deviceId}', this.destroyDevice)
    .post('/{serverId}/devices/{deviceId}', this.deviceAction)
    .post('/{serverId}/devices', this.addRemoteDevice)
    .get('/{serverId}/events', this.subscribe)
    .post('/{serverId}/events/unsubscribe', this.unsubscribe)
    .get('/{serverId}/meta', this.showMetadata)
    .get('/{serverId}/meta/{type}', this.showMetadataType);

  this.listenForMetadata();
};

ServerResource.prototype.listenForMetadata = function() {
  var self = this;
  this.server.runtime.on('deviceready', function(device) {
    if (self.typeIndex.indexOf(device.type) !== -1) {
      return;
    }

    var props = device.properties();

    var transitions = Object.keys(device._transitions).map(function(key) {
      return {
        name: key,
        fields: device._transitions[key].fields || undefined
      }
    });

    self.typeIndex.push(device.type);

    var obj = {
      type: device.type,
      properties: Object.keys(props).filter(function(key) {
        return props[key] !== undefined;
      }),
      streams: Object.keys(device._streams),
      transitions: transitions.length ? transitions : undefined
    }

    self.server.pubsub.publish('meta', obj);

    self.deviceTypes.push(obj);
  });
};

ServerResource.prototype.shouldProxy = function(env) {
  return this.server.id !== env.route.params.serverId;
};

ServerResource.prototype.proxy = function(env, next) {
  return this.server.httpServer.proxyToPeer(env, next);
};

ServerResource.prototype.subscribe = function(env, next) {
  if (!env.request.isSpdy) {
    env.response.statusCode = 426;
    return next(env);
  }

  if(this.shouldProxy(env)) {
    return this.proxy(env, next);
  }

  var self = this;
  parsed = url.parse(env.request.url, true);
  var topic = decodeURIComponent(parsed.query.topic);

  if (topic) {
    var serverId = env.route.params.serverId;
    if (!self._listeners[serverId]) {
      self._listeners[serverId] = {};
    }
    env.response.connection.setTimeout(0); // keep connection alive
    env.response.writeHead(200);
    self._listeners[serverId][topic] = env;

    function unsubscribe() {
      if (!self._listeners[serverId] || !self._listeners[serverId][topic]) {
        return next(env);
      }
      self.server.pubsub.unsubscribe(topic, self._listeners[serverId][topic]);
    }

    var qt = querytopic.parse(topic);
    if (qt) {
      topic = querytopic.format(qt);
      self.server.pubsub.subscribe(topic, env);

      setImmediate(function() {
        self.server.httpServer.eventBroker.subscribeToDeviceQuery(topic);
        env.response.on('close', unsubscribe);
        env.request.connection.on('close', unsubscribe);
      });
    } else {
      setImmediate(function() {
        self.server.pubsub.subscribe(topic, env);
        env.response.on('close', unsubscribe);
        env.request.connection.on('close', unsubscribe);
      });
    }
  } else {
    env.response.statusCode = 404;
    next(env);
  }
};

ServerResource.prototype.unsubscribe = function(env, next) {
  if (!env.request.isSpdy) {
    env.response.statusCode = 426;
    return next(env);
  }

  if(this.shouldProxy(env)) {
    return this.proxy(env, next);
  }

  var serverId = env.route.params.serverId;
  var self = this;

  env.request.getBody(function(err, body) {
    if(err) {
      env.response.statusCode = 400;
      next(env);
    } else {
      body = querystring.parse(body.toString());
      if (body.topic) {
        env.response.statusCode = 202;
        if (!self._listeners[serverId] || !self._listeners[serverId][body.topic]) {
          return next(env);
        }
        self.server.pubsub.unsubscribe(body.topic, self._listeners[serverId][body.topic]);
        next(env);
      } else {
        env.response.statusCode = 404;
        next(env);
      }
    }
  });
};

ServerResource.prototype.showMetadata = function(env, next) {
  if(this.shouldProxy(env)) {
    return this.proxy(env, next);
  }

  var context = {
    server: this.server,
    types: this.deviceTypes,
    loader: this.getServer(env),
    env: env
  };

  env.format.render('metadata', context);
  next(env);
};

ServerResource.prototype.showMetadataType = function(env, next) {
  if(this.shouldProxy(env)) {
    return this.proxy(env, next);
  }

  var typeName = env.route.params.type;

  if (this.typeIndex.indexOf(typeName) === -1) {
    env.response.statusCode = 404;
    next(env);
    return;
  }

  var type = this.deviceTypes.filter(function(t) {
    return t.type === typeName;
  })[0];

  var context = {
    server: this.server,
    type: type,
    loader: this.getServer(env),
    env: env
  };

  env.format.render('type', context);
  next(env);
};

ServerResource.prototype.showServer = function(env, next) {
  if(this.shouldProxy(env)) {
    return this.proxy(env, next);
  }

  if (env.route.query.ql) {
    return this._queryDevices(env, next);
  }

  //TODO: argo-formatter may want to take multiple arguments for a format. This context obj is a hack.
  var context = { server: this.server, devices: this.server.runtime._jsDevices, loader: this.getServer(env), env: env };
  env.format.render('server', context);
  next(env);
};

ServerResource.prototype._queryDevices = function(env, next) {
  var params = env.route.query;
  var self = this;

  if(!params.ql) {
    env.response.statusCode = 404;
    return next(env);
  } else {
    var results = [];

    var query = self.server.runtime.ql(params.ql);
    var keys = Object.keys(self.server.runtime._jsDevices);
    var max = keys.length - 1;
    var hasError = false;

    keys.forEach(function(key, i) {
      var device = self.server.runtime._jsDevices[key];

      if (hasError) {
        return;
      }

      self.server.runtime.registry.match(query, device, function(err, match) {
        if (err) {
          env.response.statusCode = 400;
          hasError = true;
          env.response.body = {
            class: ['query-error'],
            properties: {
              message: err.message
            },
            links: [
              { rel: ['self'], href: env.helpers.url.current() }
            ]
          };
          return next(env);
        }

        if (match) {
          results.push(match);
        }

        if (i === max) {
          done();
        }
      });
    });

    function done() {
      var devices = {};

      results.forEach(function(device){
        var deviceOnRuntime = self.server.runtime._jsDevices[device.id];
        if (deviceOnRuntime) {
          devices[device.id] = deviceOnRuntime;
        }
      });

      var context = {
        server: self.server,
        devices: devices,
        loader: self.getServer(env),
        env: env,
        classes:['search-results'],
        query: params.ql
      };

      env.format.render('server', context);
      next(env);
    };
  }
};

ServerResource.prototype.destroyDevice = function(env, next) {
  if(this.shouldProxy(env)) {
    return this.proxy(env, next);
  }

  var device = this.server.runtime._jsDevices[env.route.params.deviceId];
  if(!device) {
    env.response.body = 'Device does not exist';
    env.response.statusCode = 404;
    return next(env);
  }

  if (typeof device._handleRemoteDestroy !== 'function') {
    env.response.statusCode = 501;
    return next(env);
  }

  device._handleRemoteDestroy(function(err, destroyFlag) {
    if (err) {
      env.response.statusCode = 500;
      return next(env);
    }

    if(destroyFlag) {
      device.destroy(function(err) {
        if(err) {
          env.response.statusCode = 500;
          return next(env);
        } else {
          env.response.statusCode = 204;
          return next(env);
        }
      });
    } else {
      env.response.statusCode = 500;
      return next(env);
    }

  });

};

ServerResource.prototype.showDevice = function(env, next) {
  if(this.shouldProxy(env)) {
    return this.proxy(env, next);
  }

  var device = this.server.runtime._jsDevices[env.route.params.deviceId];
  if(!device) {
    env.response.body = 'Device does not exist';
    env.response.statusCode = 404;
    return next(env);
  }

  var model = {
    model: device,
    loader: this.getServer(env),
    serverName: this.server._name,
    env: env
  };

  env.format.render('device', model);

  next(env);
};

ServerResource.prototype.updateDevice = function(env, next) {
  if(this.shouldProxy(env)) {
    return this.proxy(env, next);
  }

  var device = this.server.runtime._jsDevices[env.route.params.deviceId];

  if (!device) {
    env.response.body = 'Device does not exist';
    env.response.statusCode = 404;
    return next(env);
  }

  if (env.request.headers['content-range']) {
    env.response.statusCode = 400;
    return next(env);
  }

  var self = this;
  env.request.getBody(function(err, body) {
    if (err) {
      env.response.statusCode = 400;
      return next(env);
    }

    var input;

    try {
      input = JSON.parse(body.toString());
    } catch(e) {
      env.response.statusCode = 400;
      return next(env);
    }

    if (typeof device._handleRemoteUpdate !== 'function') {
      env.response.statusCode = 501;
      return next(env);
    }

    // TODO: Check for conditional PUT using ETag.

    device._handleRemoteUpdate(input, function(err) {
      if (err) {
        env.response.statusCode = 500;
        return next(env);
      }

      var model = {
        model: device,
        loader: self.getServer(env),
        serverName: self.server._name,
        env: env
      };

      env.format.render('device', model);
      next(env);
    });
  });
};

ServerResource.prototype.deviceAction = function(env, next) {
  var self = this;

  if(this.shouldProxy(env)) {
    return this.proxy(env, next);
  }

  var device = this.server.runtime._jsDevices[env.route.params.deviceId];
  if(!device) {
    env.response.body = 'Device does not exist';
    env.response.statusCode = 404;
    return next(env);
  }

  env.request.getBody(function(err, body) {
    if (err || !body) {
      env.response.statusCode = 400;
      next(env);
      return;
    }

    body = querystring.parse(body.toString());
    return run(body);
  });

  function run(body){
    if (!body.action) {
      env.response.statusCode = 400;
      return next(env);
    }

    var action = device._transitions[body.action];
    if (!action) {
      env.response.statusCode = 400;
      return next(env);
    }

    if(!device.available(body.action)) {
      env.response.statusCode = 400;
      return next(env);
    }

    // device.call(actionName, arg1, arg2, argn, cb);
    var args = [body.action];

    if (action.fields && action.fields.length) {

      var parseErrors = [];
      action.fields.forEach(function(field) {
        if (field.name !== 'action') {
          var arg = body[field.name];
          if (field.type === 'number') {
            arg = Number(arg);

            if (isNaN(arg)) {
              parseErrors.push('Field "' + field.name  + '" expected to be a Number.');
            }
          } else if (field.type === 'date') {
            // HTML5 secifies YYYY-MM-DD for transfer over the wire. Convert it to YYYY/MM/DD for js Date object parsing
            arg = new Date(arg.replace(/-/g, "/"));

            // test if date parsed correctly
            if (isNaN(arg.getTime())) {
              parseErrors.push('Field "' + field.name  + '" expected to be a Date. eg YYYY-MM-DD');
            }
          }
          args.push(arg);
        }
      });

      // Test is any did not decode properly
      if (parseErrors.length > 0) {
        env.response.statusCode = 400;
        env.response.body = {
          class: ['input-error'],
          properties: {
            message: 'Invalid argument(s)',
            errors: parseErrors
          },
          links: [
            { rel: ['self'], href: env.helpers.url.current() }
          ]
        };
        return next(env);
      }
    }

    var cb = function(err) {
      if (err) {
        env.response.statusCode = 500;
      } else {
        var model = {
          model: device,
          loader: self.getServer(env),
          serverName: self.server._name,
          env: env
        };
        env.format.render('device', model);
      }

      next(env);
    };

    args.push(cb);
    device.call.apply(device, args);
  }
};

ServerResource.prototype.addRemoteDevice = function(env, next) {
  var self = this;
  env.request.getBody(function(err, body) {
    body = querystring.parse(body.toString());
    if(body.type) {
      if(self.httpScout.createHTTPDevice(body.type, body.id, body.name)) {
        env.response.statusCode = 201;
      } else {
        env.response.statusCode = 404;
      }
    } else {
      env.response.statusCode = 500;
    }
    next(env);
  });
};
<commit_msg>Fixed issue with spaces in hub names<commit_after>var querystring = require('querystring');
var url = require('url');
var MediaType = require('api-media-type');
var querytopic = require('../query_topic');
var streams = require('zetta-streams');
var ObjectStream = streams.ObjectStream;

var ServerResource = module.exports = function(server) {
  this.server = server;
  this.httpScout = this.server.httpScout;
  this.deviceTypes = [];
  this.typeIndex = [];
  this._listeners = {};
};

ServerResource.prototype.getServer = function(env) {
  var parsed = url.parse(env.request.url);
  var re = /^\/servers\/([^\/]+)/;
  var match = re.exec(parsed.pathname);

  var serverId = match && match[1] ? decodeURI(match[1]) : this.server.id;

  return { path: '/servers/' + encodeURI(serverId) };
};

ServerResource.prototype.init = function(config) {
  config
    .path('/servers')
    .produces(MediaType.SIREN)
    .consumes(MediaType.FORM_URLENCODED)
    .consumes(MediaType.MULTIPART_FORM_DATA)
    .consumes(MediaType.JSON)
    .get('/{serverId}', this.showServer)
    .get('/{serverId}/devices/{deviceId}', this.showDevice)
    .put('/{serverId}/devices/{deviceId}', this.updateDevice)
    .del('/{serverId}/devices/{deviceId}', this.destroyDevice)
    .post('/{serverId}/devices/{deviceId}', this.deviceAction)
    .post('/{serverId}/devices', this.addRemoteDevice)
    .get('/{serverId}/events', this.subscribe)
    .post('/{serverId}/events/unsubscribe', this.unsubscribe)
    .get('/{serverId}/meta', this.showMetadata)
    .get('/{serverId}/meta/{type}', this.showMetadataType);

  this.listenForMetadata();
};

ServerResource.prototype.listenForMetadata = function() {
  var self = this;
  this.server.runtime.on('deviceready', function(device) {
    if (self.typeIndex.indexOf(device.type) !== -1) {
      return;
    }

    var props = device.properties();

    var transitions = Object.keys(device._transitions).map(function(key) {
      return {
        name: key,
        fields: device._transitions[key].fields || undefined
      }
    });

    self.typeIndex.push(device.type);

    var obj = {
      type: device.type,
      properties: Object.keys(props).filter(function(key) {
        return props[key] !== undefined;
      }),
      streams: Object.keys(device._streams),
      transitions: transitions.length ? transitions : undefined
    }

    self.server.pubsub.publish('meta', obj);

    self.deviceTypes.push(obj);
  });
};

ServerResource.prototype.shouldProxy = function(env) {
  return this.server.id !== env.route.params.serverId;
};

ServerResource.prototype.proxy = function(env, next) {
  return this.server.httpServer.proxyToPeer(env, next);
};

ServerResource.prototype.subscribe = function(env, next) {
  if (!env.request.isSpdy) {
    env.response.statusCode = 426;
    return next(env);
  }

  if(this.shouldProxy(env)) {
    return this.proxy(env, next);
  }

  var self = this;
  parsed = url.parse(env.request.url, true);
  var topic = decodeURIComponent(parsed.query.topic);

  if (topic) {
    var serverId = env.route.params.serverId;
    if (!self._listeners[serverId]) {
      self._listeners[serverId] = {};
    }
    env.response.connection.setTimeout(0); // keep connection alive
    env.response.writeHead(200);
    self._listeners[serverId][topic] = env;

    function unsubscribe() {
      if (!self._listeners[serverId] || !self._listeners[serverId][topic]) {
        return next(env);
      }
      self.server.pubsub.unsubscribe(topic, self._listeners[serverId][topic]);
    }

    var qt = querytopic.parse(topic);
    if (qt) {
      topic = querytopic.format(qt);
      self.server.pubsub.subscribe(topic, env);

      setImmediate(function() {
        self.server.httpServer.eventBroker.subscribeToDeviceQuery(topic);
        env.response.on('close', unsubscribe);
        env.request.connection.on('close', unsubscribe);
      });
    } else {
      setImmediate(function() {
        self.server.pubsub.subscribe(topic, env);
        env.response.on('close', unsubscribe);
        env.request.connection.on('close', unsubscribe);
      });
    }
  } else {
    env.response.statusCode = 404;
    next(env);
  }
};

ServerResource.prototype.unsubscribe = function(env, next) {
  if (!env.request.isSpdy) {
    env.response.statusCode = 426;
    return next(env);
  }

  if(this.shouldProxy(env)) {
    return this.proxy(env, next);
  }

  var serverId = env.route.params.serverId;
  var self = this;

  env.request.getBody(function(err, body) {
    if(err) {
      env.response.statusCode = 400;
      next(env);
    } else {
      body = querystring.parse(body.toString());
      if (body.topic) {
        env.response.statusCode = 202;
        if (!self._listeners[serverId] || !self._listeners[serverId][body.topic]) {
          return next(env);
        }
        self.server.pubsub.unsubscribe(body.topic, self._listeners[serverId][body.topic]);
        next(env);
      } else {
        env.response.statusCode = 404;
        next(env);
      }
    }
  });
};

ServerResource.prototype.showMetadata = function(env, next) {
  if(this.shouldProxy(env)) {
    return this.proxy(env, next);
  }

  var context = {
    server: this.server,
    types: this.deviceTypes,
    loader: this.getServer(env),
    env: env
  };

  env.format.render('metadata', context);
  next(env);
};

ServerResource.prototype.showMetadataType = function(env, next) {
  if(this.shouldProxy(env)) {
    return this.proxy(env, next);
  }

  var typeName = env.route.params.type;

  if (this.typeIndex.indexOf(typeName) === -1) {
    env.response.statusCode = 404;
    next(env);
    return;
  }

  var type = this.deviceTypes.filter(function(t) {
    return t.type === typeName;
  })[0];

  var context = {
    server: this.server,
    type: type,
    loader: this.getServer(env),
    env: env
  };

  env.format.render('type', context);
  next(env);
};

ServerResource.prototype.showServer = function(env, next) {
  if(this.shouldProxy(env)) {
    return this.proxy(env, next);
  }

  if (env.route.query.ql) {
    return this._queryDevices(env, next);
  }

  //TODO: argo-formatter may want to take multiple arguments for a format. This context obj is a hack.
  var context = { server: this.server, devices: this.server.runtime._jsDevices, loader: this.getServer(env), env: env };
  env.format.render('server', context);
  next(env);
};

ServerResource.prototype._queryDevices = function(env, next) {
  var params = env.route.query;
  var self = this;

  if(!params.ql) {
    env.response.statusCode = 404;
    return next(env);
  } else {
    var results = [];

    var query = self.server.runtime.ql(params.ql);
    var keys = Object.keys(self.server.runtime._jsDevices);
    var max = keys.length - 1;
    var hasError = false;

    keys.forEach(function(key, i) {
      var device = self.server.runtime._jsDevices[key];

      if (hasError) {
        return;
      }

      self.server.runtime.registry.match(query, device, function(err, match) {
        if (err) {
          env.response.statusCode = 400;
          hasError = true;
          env.response.body = {
            class: ['query-error'],
            properties: {
              message: err.message
            },
            links: [
              { rel: ['self'], href: env.helpers.url.current() }
            ]
          };
          return next(env);
        }

        if (match) {
          results.push(match);
        }

        if (i === max) {
          done();
        }
      });
    });

    function done() {
      var devices = {};

      results.forEach(function(device){
        var deviceOnRuntime = self.server.runtime._jsDevices[device.id];
        if (deviceOnRuntime) {
          devices[device.id] = deviceOnRuntime;
        }
      });

      var context = {
        server: self.server,
        devices: devices,
        loader: self.getServer(env),
        env: env,
        classes:['search-results'],
        query: params.ql
      };

      env.format.render('server', context);
      next(env);
    };
  }
};

ServerResource.prototype.destroyDevice = function(env, next) {
  if(this.shouldProxy(env)) {
    return this.proxy(env, next);
  }

  var device = this.server.runtime._jsDevices[env.route.params.deviceId];
  if(!device) {
    env.response.body = 'Device does not exist';
    env.response.statusCode = 404;
    return next(env);
  }

  if (typeof device._handleRemoteDestroy !== 'function') {
    env.response.statusCode = 501;
    return next(env);
  }

  device._handleRemoteDestroy(function(err, destroyFlag) {
    if (err) {
      env.response.statusCode = 500;
      return next(env);
    }

    if(destroyFlag) {
      device.destroy(function(err) {
        if(err) {
          env.response.statusCode = 500;
          return next(env);
        } else {
          env.response.statusCode = 204;
          return next(env);
        }
      });
    } else {
      env.response.statusCode = 500;
      return next(env);
    }

  });

};

ServerResource.prototype.showDevice = function(env, next) {
  if(this.shouldProxy(env)) {
    return this.proxy(env, next);
  }

  var device = this.server.runtime._jsDevices[env.route.params.deviceId];
  if(!device) {
    env.response.body = 'Device does not exist';
    env.response.statusCode = 404;
    return next(env);
  }

  var model = {
    model: device,
    loader: this.getServer(env),
    serverName: this.server._name,
    env: env
  };

  env.format.render('device', model);

  next(env);
};

ServerResource.prototype.updateDevice = function(env, next) {
  if(this.shouldProxy(env)) {
    return this.proxy(env, next);
  }

  var device = this.server.runtime._jsDevices[env.route.params.deviceId];

  if (!device) {
    env.response.body = 'Device does not exist';
    env.response.statusCode = 404;
    return next(env);
  }

  if (env.request.headers['content-range']) {
    env.response.statusCode = 400;
    return next(env);
  }

  var self = this;
  env.request.getBody(function(err, body) {
    if (err) {
      env.response.statusCode = 400;
      return next(env);
    }

    var input;

    try {
      input = JSON.parse(body.toString());
    } catch(e) {
      env.response.statusCode = 400;
      return next(env);
    }

    if (typeof device._handleRemoteUpdate !== 'function') {
      env.response.statusCode = 501;
      return next(env);
    }

    // TODO: Check for conditional PUT using ETag.

    device._handleRemoteUpdate(input, function(err) {
      if (err) {
        env.response.statusCode = 500;
        return next(env);
      }

      var model = {
        model: device,
        loader: self.getServer(env),
        serverName: self.server._name,
        env: env
      };

      env.format.render('device', model);
      next(env);
    });
  });
};

ServerResource.prototype.deviceAction = function(env, next) {
  var self = this;

  if(this.shouldProxy(env)) {
    return this.proxy(env, next);
  }

  var device = this.server.runtime._jsDevices[env.route.params.deviceId];
  if(!device) {
    env.response.body = 'Device does not exist';
    env.response.statusCode = 404;
    return next(env);
  }

  env.request.getBody(function(err, body) {
    if (err || !body) {
      env.response.statusCode = 400;
      next(env);
      return;
    }

    body = querystring.parse(body.toString());
    return run(body);
  });

  function run(body){
    if (!body.action) {
      env.response.statusCode = 400;
      return next(env);
    }

    var action = device._transitions[body.action];
    if (!action) {
      env.response.statusCode = 400;
      return next(env);
    }

    if(!device.available(body.action)) {
      env.response.statusCode = 400;
      return next(env);
    }

    // device.call(actionName, arg1, arg2, argn, cb);
    var args = [body.action];

    if (action.fields && action.fields.length) {

      var parseErrors = [];
      action.fields.forEach(function(field) {
        if (field.name !== 'action') {
          var arg = body[field.name];
          if (field.type === 'number') {
            arg = Number(arg);

            if (isNaN(arg)) {
              parseErrors.push('Field "' + field.name  + '" expected to be a Number.');
            }
          } else if (field.type === 'date') {
            // HTML5 secifies YYYY-MM-DD for transfer over the wire. Convert it to YYYY/MM/DD for js Date object parsing
            arg = new Date(arg.replace(/-/g, "/"));

            // test if date parsed correctly
            if (isNaN(arg.getTime())) {
              parseErrors.push('Field "' + field.name  + '" expected to be a Date. eg YYYY-MM-DD');
            }
          }
          args.push(arg);
        }
      });

      // Test is any did not decode properly
      if (parseErrors.length > 0) {
        env.response.statusCode = 400;
        env.response.body = {
          class: ['input-error'],
          properties: {
            message: 'Invalid argument(s)',
            errors: parseErrors
          },
          links: [
            { rel: ['self'], href: env.helpers.url.current() }
          ]
        };
        return next(env);
      }
    }

    var cb = function(err) {
      if (err) {
        env.response.statusCode = 500;
      } else {
        var model = {
          model: device,
          loader: self.getServer(env),
          serverName: self.server._name,
          env: env
        };
        env.format.render('device', model);
      }

      next(env);
    };

    args.push(cb);
    device.call.apply(device, args);
  }
};

ServerResource.prototype.addRemoteDevice = function(env, next) {
  var self = this;
  env.request.getBody(function(err, body) {
    body = querystring.parse(body.toString());
    if(body.type) {
      if(self.httpScout.createHTTPDevice(body.type, body.id, body.name)) {
        env.response.statusCode = 201;
      } else {
        env.response.statusCode = 404;
      }
    } else {
      env.response.statusCode = 500;
    }
    next(env);
  });
};
<|endoftext|>