<commit_before>import {fromJS, Map, Set} from 'immutable'
import {call, put, select} from 'redux-saga/effects';
import {Apis} from 'shared/api_client';

/**
    This loadFollows both 'blog' and 'ignore'
*/

//fetch for follow/following count
export function* fetchFollowCount(account) {
    const counts = yield call(Apis.follow, 'get_follow_count', account)
    yield put({type: 'global/UPDATE', payload: {
        key: ['follow_count', account],
        updater: m => m.mergeDeep({'follower_count': counts.follower_count,
        'following_count': counts.following_count})
    }})
}

// Test limit with 2 (not 1, infinate looping)
export function* loadFollows(method, account, type, force = false) {
    if(yield select(state => state.global.getIn(['follow', method, account, type + '_loading']))) {
        // console.log('Already loading', method, account, type)
        return
    }

    if(!force) {
        const hasResult = yield select(state => state.global.hasIn(['follow', method, account, type + '_result']))
        if(hasResult) {
            // console.log('Already loaded', method, account, type)
            return
        }
    }

    yield put({type: 'global/UPDATE', payload: {
        key: ['follow', method, account],
        notSet: Map(),
        updater: m => m.set(type + '_loading', true),
    }})

    yield loadFollowsLoop(method, account, type)
}

function* loadFollowsLoop(method, account, type, start = '', limit = 100) {
    method == "get_followers" ? limit = 1000 : limit;
    const res = fromJS(yield Apis.follow(method, account, start, type, limit));
    // console.log('res.toJS()', res.toJS())

    let cnt = 0
    let lastAccountName = null

    yield put({type: 'global/UPDATE', payload: {
        key: ['follow_inprogress', method, account],
        notSet: Map(),
        updater: m => {
            m = m.asMutable()
            res.forEach(value => {
                cnt++

                const whatList = value.get('what')
                const accountNameKey = method === "get_following" ? "following" : "follower";
                const accountName = lastAccountName = value.get(accountNameKey)
                whatList.forEach(what => {
                    //currently this is always true: what === type
                    m.update(what, Set(), s => s.add(accountName))
                })
            })
            return m.asImmutable()
        }
    }})

    if(cnt === limit) {
        // This is paging each block of up to limit results
        yield call(loadFollowsLoop, method, account, type, lastAccountName)
    } else {
        // This condition happens only once at the very end of the list.
        // Every account has a different followers and following list for: blog, ignore
        yield put({type: 'global/UPDATE', payload: {
            key: [],
            updater: m => {
                m = m.asMutable()

                const result = m.getIn(['follow_inprogress', method, account, type], Set())
                m.deleteIn(['follow_inprogress', method, account, type])
                m.updateIn(['follow', method, account], Map(), mm => mm.merge({
                    // Count may be set separately without loading the full xxx_result set
                    [type + '_count']: result.size,
                    [type + '_result']: result.sort().reverse(),
                    [type + '_loading']: false,
                }))
                return m.asImmutable()
            }
        }})
    }
}
<commit_msg>fix ternary op, eslint<commit_after>import {fromJS, Map, Set} from 'immutable'
import {call, put, select} from 'redux-saga/effects';
import {Apis} from 'shared/api_client';

/**
    This loadFollows both 'blog' and 'ignore'
*/

//fetch for follow/following count
export function* fetchFollowCount(account) {
    const counts = yield call(Apis.follow, 'get_follow_count', account)
    yield put({
        type: 'global/UPDATE',
        payload: {
            key: ['follow_count', account],
            updater: m => m.mergeDeep({
                follower_count: counts.follower_count,
                following_count: counts.following_count})
    }})
}

// Test limit with 2 (not 1, infinate looping)
export function* loadFollows(method, account, type, force = false) {
    if(yield select(state => state.global.getIn(['follow', method, account, type + '_loading']))) {
        // console.log('Already loading', method, account, type)
        return
    }

    if(!force) {
        const hasResult = yield select(state => state.global.hasIn(['follow', method, account, type + '_result']))
        if(hasResult) {
            // console.log('Already loaded', method, account, type)
            return
        }
    }

    yield put({
        type: 'global/UPDATE',
        payload: {
            key: ['follow', method, account],
            notSet: Map(),
            updater: m => m.set(type + '_loading', true),
    }})

    yield loadFollowsLoop(method, account, type)
}

function* loadFollowsLoop(method, account, type, start = '', limit = 100) {
    if(method === "get_followers") limit = 1000;
    const res = fromJS(yield Apis.follow(method, account, start, type, limit));
    // console.log('res.toJS()', res.toJS())

    let cnt = 0
    let lastAccountName = null

    yield put({type: 'global/UPDATE', payload: {
        key: ['follow_inprogress', method, account],
        notSet: Map(),
        updater: (m) => {
            m = m.asMutable()
            res.forEach((value) => {
                cnt += 1;

                const whatList = value.get('what')
                const accountNameKey = method === "get_following" ? "following" : "follower";
                const accountName = lastAccountName = value.get(accountNameKey)
                whatList.forEach((what) => {
                    //currently this is always true: what === type
                    m.update(what, Set(), s => s.add(accountName))
                })
            })
            return m.asImmutable()
        }
    }})

    if(cnt === limit) {
        // This is paging each block of up to limit results
        yield call(loadFollowsLoop, method, account, type, lastAccountName)
    } else {
        // This condition happens only once at the very end of the list.
        // Every account has a different followers and following list for: blog, ignore
        yield put({type: 'global/UPDATE', payload: {
            key: [],
            updater: (m) => {
                m = m.asMutable()

                const result = m.getIn(['follow_inprogress', method, account, type], Set())
                m.deleteIn(['follow_inprogress', method, account, type])
                m.updateIn(['follow', method, account], Map(), mm => mm.merge({
                    // Count may be set separately without loading the full xxx_result set
                    [type + '_count']: result.size,
                    [type + '_result']: result.sort().reverse(),
                    [type + '_loading']: false,
                }))
                return m.asImmutable()
            }
        }})
    }
}
<|endoftext|>


<commit_before>'use strict';

require(__dirname + '/js/tray.js');

const DomainUtil = require(__dirname + '/js/utils/domain-util.js');
const {linkIsInternal, skipImages} = require(__dirname + '/../main/link-helper');
const {shell, ipcRenderer} = require('electron');

class ServerManagerView {
	constructor() {
		this.$tabsContainer = document.getElementById('tabs-container');

		const $actionsContainer = document.getElementById('actions-container');
		this.$addServerButton = $actionsContainer.querySelector('#add-action');
		this.$settingsButton = $actionsContainer.querySelector('#settings-action');
		this.$content = document.getElementById('content');

		this.isLoading = false;
		this.settingsTabIndex = -1;
		this.activeTabIndex = -1;
		this.zoomFactors = [];
	}

	init() {
		this.domainUtil = new DomainUtil();
		this.initTabs();
		this.initActions();
		this.registerIpcs();
	}

	initTabs() {
		const servers = this.domainUtil.getDomains();
		if (servers.length > 0) {
			for (const server of servers) {
				this.initTab(server);
			}

			this.activateTab(0);
		} else {
			this.openSettings();
		}
	}

	initTab(tab) {
		const {
			url,
			icon
		} = tab;
		const tabTemplate = tab.template || `

`;
		const $tab = this.insertNode(tabTemplate);
		const index = this.$tabsContainer.childNodes.length;
		this.$tabsContainer.appendChild($tab);
		$tab.addEventListener('click', this.activateTab.bind(this, index));
	}

	initWebView(url, index, nodeIntegration = false) {
		const webViewTemplate = `
			<webview
				id="webview-${index}"
				class="loading"
				src="${url}"
				${nodeIntegration ? 'nodeIntegration' : ''}
				disablewebsecurity
				preload="js/preload.js"
				webpreferences="allowRunningInsecureContent, javascript=yes">
			</webview>
		`;
		const $webView = this.insertNode(webViewTemplate);
		this.$content.appendChild($webView);
		this.isLoading = true;
		this.registerListeners($webView, index);
		this.zoomFactors[index] = 1;
	}

	startLoading(url, index) {
		const $activeWebView = document.getElementById(`webview-${this.activeTabIndex}`);
		if ($activeWebView) {
			$activeWebView.classList.add('disabled');
		}
		const $webView = document.getElementById(`webview-${index}`);
		if ($webView === null) {
			this.initWebView(url, index, this.settingsTabIndex === index);
		} else {
			this.updateBadge(index);
			$webView.classList.remove('disabled');
			$webView.focus();
		}
	}

	endLoading(index) {
		const $webView = document.getElementById(`webview-${index}`);
		this.isLoading = false;
		$webView.classList.remove('loading');
	}

	initActions() {
		this.$addServerButton.addEventListener('click', this.openSettings.bind(this));
		this.$settingsButton.addEventListener('click', this.openSettings.bind(this));
	}

	openSettings() {
		if (this.settingsTabIndex !== -1) {
			this.activateTab(this.settingsTabIndex);
			return;
		}
		const url = 'file://' + __dirname + '/preference.html';

		const settingsTabTemplate = `

						settings

`;
		this.initTab({
			alias: 'Settings',
			url,
			template: settingsTabTemplate
		});

		this.settingsTabIndex = this.$tabsContainer.childNodes.length - 1;
		this.activateTab(this.settingsTabIndex);
	}

	activateTab(index) {
		if (this.isLoading) {
			return;
		}

		if (this.activeTabIndex !== -1) {
			if (this.activeTabIndex === index) {
				return;
			} else {
				this.getTabAt(this.activeTabIndex).classList.remove('active');
			}
		}

		const $tab = this.getTabAt(index);
		$tab.classList.add('active');

		const domain = $tab.getAttribute('domain');
		this.startLoading(domain, index);
		this.activeTabIndex = index;
	}

	insertNode(html) {
		const wrapper = document.createElement('div');
		wrapper.innerHTML = html;
		return wrapper.firstElementChild;
	}

	getTabAt(index) {
		return this.$tabsContainer.childNodes[index];
	}

	updateBadge(index) {
		const $activeWebView = document.getElementById(`webview-${index}`);
		const title = $activeWebView.getTitle();
		let messageCount = (/\(([0-9]+)\)/).exec(title);
		messageCount = messageCount ? Number(messageCount[1]) : 0;
		ipcRenderer.send('update-badge', messageCount);
	}

	registerListeners($webView, index) {
		$webView.addEventListener('new-window', event => {
			const {url} = event;
			const domainPrefix = this.domainUtil.getDomain(this.activeTabIndex).url;
			if (linkIsInternal(domainPrefix, url) && url.match(skipImages) === null) {
				event.preventDefault();
				return $webView.loadURL(url);
			}
			event.preventDefault();
			shell.openExternal(url);
		});
		$webView.addEventListener('dom-ready', this.endLoading.bind(this, index));
		$webView.addEventListener('dom-ready', () => {
			// We need to wait until the page title is ready to get badge count
			setTimeout(() => this.updateBadge(index), 1000);
		});
		$webView.addEventListener('dom-ready', () => {
			$webView.focus();
		});
		$webView.addEventListener('focus', () => {
			console.log('webview focus...', $webView.focus)
		})
	}

	registerIpcs() {
		// ipcRenderer.on('reload', () => {
		// 	const activeWebview = document.getElementById(`webview-${this.activeTabIndex}`);
		// 	activeWebview.reload();
		// });

		ipcRenderer.on('back', () => {
			const activeWebview = document.getElementById(`webview-${this.activeTabIndex}`);
			if (activeWebview.canGoBack()) {
				activeWebview.goBack();
			}
		});

		ipcRenderer.on('focus', () => {
			const activeWebview = document.getElementById(`webview-${this.activeTabIndex}`);
			activeWebview.focus()
		});

		ipcRenderer.on('forward', () => {
			const activeWebview = document.getElementById(`webview-${this.activeTabIndex}`);
			if (activeWebview.canGoForward()) {
				activeWebview.goForward();
			}
		});

		// Handle zooming functionality
		ipcRenderer.on('zoomIn', () => {
			const activeWebview = document.getElementById(`webview-${this.activeTabIndex}`);
			this.zoomFactors[this.activeTabIndex] += 0.1;
			activeWebview.setZoomFactor(this.zoomFactors[this.activeTabIndex]);
		});

		ipcRenderer.on('zoomOut', () => {
			const activeWebview = document.getElementById(`webview-${this.activeTabIndex}`);
			this.zoomFactors[this.activeTabIndex] -= 0.1;
			activeWebview.setZoomFactor(this.zoomFactors[this.activeTabIndex]);
		});

		ipcRenderer.on('zoomActualSize', () => {
			const activeWebview = document.getElementById(`webview-${this.activeTabIndex}`);
			this.zoomFactors[this.activeTabIndex] = 1;
			activeWebview.setZoomFactor(this.zoomFactors[this.activeTabIndex]);
		});

		ipcRenderer.on('log-out', () => {
			const activeWebview = document.getElementById(`webview-${this.activeTabIndex}`);
			activeWebview.executeJavaScript('logout()');
		});

		ipcRenderer.on('shortcut', () => {
			const activeWebview = document.getElementById(`webview-${this.activeTabIndex}`);
			activeWebview.executeJavaScript('shortcut()');
		});

		ipcRenderer.on('open-settings', () => {
			if (this.settingsTabIndex === -1) {
				this.openSettings();
			} else {
				this.activateTab(this.settingsTabIndex);
			}
		});
	}
}

window.onload = () => {
	const serverManagerView = new ServerManagerView();
	serverManagerView.init();
};
<commit_msg>remove unneeded listener<commit_after>'use strict';

require(__dirname + '/js/tray.js');

const DomainUtil = require(__dirname + '/js/utils/domain-util.js');
const {linkIsInternal, skipImages} = require(__dirname + '/../main/link-helper');
const {shell, ipcRenderer} = require('electron');

class ServerManagerView {
	constructor() {
		this.$tabsContainer = document.getElementById('tabs-container');

		const $actionsContainer = document.getElementById('actions-container');
		this.$addServerButton = $actionsContainer.querySelector('#add-action');
		this.$settingsButton = $actionsContainer.querySelector('#settings-action');
		this.$content = document.getElementById('content');

		this.isLoading = false;
		this.settingsTabIndex = -1;
		this.activeTabIndex = -1;
		this.zoomFactors = [];
	}

	init() {
		this.domainUtil = new DomainUtil();
		this.initTabs();
		this.initActions();
		this.registerIpcs();
	}

	initTabs() {
		const servers = this.domainUtil.getDomains();
		if (servers.length > 0) {
			for (const server of servers) {
				this.initTab(server);
			}

			this.activateTab(0);
		} else {
			this.openSettings();
		}
	}

	initTab(tab) {
		const {
			url,
			icon
		} = tab;
		const tabTemplate = tab.template || `

`;
		const $tab = this.insertNode(tabTemplate);
		const index = this.$tabsContainer.childNodes.length;
		this.$tabsContainer.appendChild($tab);
		$tab.addEventListener('click', this.activateTab.bind(this, index));
	}

	initWebView(url, index, nodeIntegration = false) {
		const webViewTemplate = `
			<webview
				id="webview-${index}"
				class="loading"
				src="${url}"
				${nodeIntegration ? 'nodeIntegration' : ''}
				disablewebsecurity
				preload="js/preload.js"
				webpreferences="allowRunningInsecureContent, javascript=yes">
			</webview>
		`;
		const $webView = this.insertNode(webViewTemplate);
		this.$content.appendChild($webView);
		this.isLoading = true;
		this.registerListeners($webView, index);
		this.zoomFactors[index] = 1;
	}

	startLoading(url, index) {
		const $activeWebView = document.getElementById(`webview-${this.activeTabIndex}`);
		if ($activeWebView) {
			$activeWebView.classList.add('disabled');
		}
		const $webView = document.getElementById(`webview-${index}`);
		if ($webView === null) {
			this.initWebView(url, index, this.settingsTabIndex === index);
		} else {
			this.updateBadge(index);
			$webView.classList.remove('disabled');
			$webView.focus();
		}
	}

	endLoading(index) {
		const $webView = document.getElementById(`webview-${index}`);
		this.isLoading = false;
		$webView.classList.remove('loading');
	}

	initActions() {
		this.$addServerButton.addEventListener('click', this.openSettings.bind(this));
		this.$settingsButton.addEventListener('click', this.openSettings.bind(this));
	}

	openSettings() {
		if (this.settingsTabIndex !== -1) {
			this.activateTab(this.settingsTabIndex);
			return;
		}
		const url = 'file://' + __dirname + '/preference.html';

		const settingsTabTemplate = `

						settings

`;
		this.initTab({
			alias: 'Settings',
			url,
			template: settingsTabTemplate
		});

		this.settingsTabIndex = this.$tabsContainer.childNodes.length - 1;
		this.activateTab(this.settingsTabIndex);
	}

	activateTab(index) {
		if (this.isLoading) {
			return;
		}

		if (this.activeTabIndex !== -1) {
			if (this.activeTabIndex === index) {
				return;
			} else {
				this.getTabAt(this.activeTabIndex).classList.remove('active');
			}
		}

		const $tab = this.getTabAt(index);
		$tab.classList.add('active');

		const domain = $tab.getAttribute('domain');
		this.startLoading(domain, index);
		this.activeTabIndex = index;
	}

	insertNode(html) {
		const wrapper = document.createElement('div');
		wrapper.innerHTML = html;
		return wrapper.firstElementChild;
	}

	getTabAt(index) {
		return this.$tabsContainer.childNodes[index];
	}

	updateBadge(index) {
		const $activeWebView = document.getElementById(`webview-${index}`);
		const title = $activeWebView.getTitle();
		let messageCount = (/\(([0-9]+)\)/).exec(title);
		messageCount = messageCount ? Number(messageCount[1]) : 0;
		ipcRenderer.send('update-badge', messageCount);
	}

	registerListeners($webView, index) {
		$webView.addEventListener('new-window', event => {
			const {url} = event;
			const domainPrefix = this.domainUtil.getDomain(this.activeTabIndex).url;
			if (linkIsInternal(domainPrefix, url) && url.match(skipImages) === null) {
				event.preventDefault();
				return $webView.loadURL(url);
			}
			event.preventDefault();
			shell.openExternal(url);
		});
		$webView.addEventListener('dom-ready', this.endLoading.bind(this, index));
		$webView.addEventListener('dom-ready', () => {
			// We need to wait until the page title is ready to get badge count
			setTimeout(() => this.updateBadge(index), 1000);
		});
		$webView.addEventListener('dom-ready', () => {
			$webView.focus();
		});
	}

	registerIpcs() {
		// ipcRenderer.on('reload', () => {
		// 	const activeWebview = document.getElementById(`webview-${this.activeTabIndex}`);
		// 	activeWebview.reload();
		// });

		ipcRenderer.on('back', () => {
			const activeWebview = document.getElementById(`webview-${this.activeTabIndex}`);
			if (activeWebview.canGoBack()) {
				activeWebview.goBack();
			}
		});

		ipcRenderer.on('focus', () => {
			const activeWebview = document.getElementById(`webview-${this.activeTabIndex}`);
			activeWebview.focus()
		});

		ipcRenderer.on('forward', () => {
			const activeWebview = document.getElementById(`webview-${this.activeTabIndex}`);
			if (activeWebview.canGoForward()) {
				activeWebview.goForward();
			}
		});

		// Handle zooming functionality
		ipcRenderer.on('zoomIn', () => {
			const activeWebview = document.getElementById(`webview-${this.activeTabIndex}`);
			this.zoomFactors[this.activeTabIndex] += 0.1;
			activeWebview.setZoomFactor(this.zoomFactors[this.activeTabIndex]);
		});

		ipcRenderer.on('zoomOut', () => {
			const activeWebview = document.getElementById(`webview-${this.activeTabIndex}`);
			this.zoomFactors[this.activeTabIndex] -= 0.1;
			activeWebview.setZoomFactor(this.zoomFactors[this.activeTabIndex]);
		});

		ipcRenderer.on('zoomActualSize', () => {
			const activeWebview = document.getElementById(`webview-${this.activeTabIndex}`);
			this.zoomFactors[this.activeTabIndex] = 1;
			activeWebview.setZoomFactor(this.zoomFactors[this.activeTabIndex]);
		});

		ipcRenderer.on('log-out', () => {
			const activeWebview = document.getElementById(`webview-${this.activeTabIndex}`);
			activeWebview.executeJavaScript('logout()');
		});

		ipcRenderer.on('shortcut', () => {
			const activeWebview = document.getElementById(`webview-${this.activeTabIndex}`);
			activeWebview.executeJavaScript('shortcut()');
		});

		ipcRenderer.on('open-settings', () => {
			if (this.settingsTabIndex === -1) {
				this.openSettings();
			} else {
				this.activateTab(this.settingsTabIndex);
			}
		});
	}
}

window.onload = () => {
	const serverManagerView = new ServerManagerView();
	serverManagerView.init();
};
<|endoftext|>


<commit_before>'use strict';

var moment = require('moment');

module.exports = (bot, config) => {
    if (typeof config.data.timers === 'undefined') {
        config.data.timers = [];
    }
    const timers = config.data.timers;
    const actions = {
        deop: bot.takeOp,
        devoice: bot.takeVoice,
        unquiet: bot.takeQuiet
    };

    function addTimer(time, action, target, channel) {
        let timer = {
            time: time,
            action: action,
            target: target,
            channel: channel
        };
        timers.push(timer);
        setTimeout(executeTimer, moment(time).diff(moment()), timer);
        config.save();
    }

    function removeTimer(timer) {
        let location = timers.indexOf(timer);
        timers.splice(location, 1);
        config.save();
    }

    function executeTimer(timer) {
        try {
            actions[timer.action](timer.target, timer.channel);
            removeTimer(timer);
        } catch (e) {
            setTimeout(executeTimer, 10 * 1000, timer);
        }

    }

    function parseTime(args) {
        args = args.split(' ');

        for (let i = 0; i < args.length; i++) {
            if ((/^\d+$/).test(args[i])) {
                let unit = 'seconds';
                if ((/^\w+$/).test(args[i + 1])) unit = moment.normalizeUnits(args[i + 1]) || unit;
                return moment().add(args[i], unit);

            } else if (/^\d+\w$/.test(args[i])) {
                let time = args[i].replace(/[^\d]/gi, '');
                let unit = args[i].replace(/[\d]/gi, '');
                return moment().add(time, moment.normalizeUnits(unit));
            }
        }
    }

    // Load timers on plugin load
    for (let timer of timers) {
        let time = moment(timer.time).diff(moment());
        time = Math.max(time, 15 * 1000); // Timeout to make sure the bot is connected.
        setTimeout(executeTimer, time, timer);
    }

    return {
        commands: {
            op: [
                {
                    pattern: /^(\S*)$/,
                    requires: 'operator',
                    execute: (event, user) => {
                        if (user.length === 0) user = event.nick;
                        bot.giveOp(user, event.channel)
                            .then(() => {
                                bot.notify(event.nick, `User ${user} was opped.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not op user: ${error}`);
                            });
                    }
                },
                {
                    pattern: /^(\S*) (\S+) *(\S*)$/,
                    requires: 'operator',
                    execute: (event, user) => {
                        if (user.length === 0) user = event.nick;
                        bot.giveOp(user, event.channel)
                            .then(() => {
                                let time = parseTime(event.args);
                                addTimer(time, 'deop', user, event.channel);

                                bot.notify(event.nick, `User ${user} was opped.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not op user: ${error}`);
                            });
                    }
                },
                'Usage: op [USER_NAME] [TIME_STAMP]'
            ],
            deop: [
                {
                    pattern: /^(\S*)$/,
                    requires: 'operator',
                    execute: (event, user) => {
                        if (user.length === 0) user = event.nick;
                        bot.takeOp(user, event.channel)
                            .then(() => {
                                bot.notify(event.nick, `User ${user} was deopped.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not deop user: ${error}`);
                            });
                    }
                },
                'Usage: deop [USER_NAME]'
            ],
            voice: [
                {
                    pattern: /^(\S*)$/,
                    requires: 'operator',
                    execute: (event, user) => {
                        if (user.length === 0) user = event.nick;
                        bot.giveVoice(user, event.channel)
                            .then(() => {
                                bot.notify(event.nick, `User ${user} was voiced.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not voice user: ${error}`);
                            });
                    }
                },
                {
                    pattern: /^(\S*) (\S+) *(\S*)$/,
                    requires: 'operator',
                    execute: (event, user) => {
                        if (user.length === 0) user = event.nick;
                        bot.giveVoice(user, event.channel)
                            .then(() => {
                                let time = parseTime(event.args);
                                addTimer(time, 'devoice', user, event.channel);

                                bot.notify(event.nick, `User ${user} was voiced.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not voice user: ${error}`);
                            });
                    }
                },
                'Usage: voice [USER_NAME]'
            ],
            devoice: [
                {
                    pattern: /^(\S*)$/,
                    requires: 'operator',
                    execute: (event, user) => {
                        if (user.length === 0) user = event.nick;
                        bot.takeVoice(user, event.channel)
                            .then(() => {
                                bot.notify(event.nick, `User ${user} was devoiced.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not devoice user: ${error}`);
                            });
                    }
                },
                'Usage: devoice [USER_NAME]'
            ],
            quiet: [
                {
                    pattern: /^(\S+)$/,
                    requires: 'operator',
                    execute: (event, target) => {
                        bot.users.get(target)
                            .then((whois) => {
                                return bot.giveQuiet(`*!*@${whois.host}`, event.channel);
                            })
                            .then(() => {
                                bot.notify(event.nick, `${target} has been quieted.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not quiet ${target}: ${error}`);
                            });
                    }
                },
                {
                    pattern: /^(\S*) (\S+) *(\S*)$/,
                    requires: 'operator',
                    execute: (event, target) => {
                        bot.users.get(target)
                            .then((whois) => {
                                let time = parseTime(event.args);
                                addTimer(time, 'unquiet', `*!*@${whois.host}`, event.channel);

                                return bot.giveQuiet(`*!*@${whois.host}`, event.channel);
                            })
                            .then(() => {
                                bot.notify(event.nick, `${target} has been quieted.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not quiet ${target}: ${error}`);
                            });
                    }
                },
                'Usage: quiet [USER_NAME]'
            ],
            unquiet: [
                {
                    pattern: /^(\S+)$/,
                    requires: 'operator',
                    execute: (event, target) => {
                        bot.users.get(target)
                            .then((whois) => {
                                return bot.takeQuiet(`*!*@${whois.host}`, event.channel);
                            })
                            .then(() => {
                                bot.notify(event.nick, `${target} has been unquieted.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not unquiet ${target}: ${error}`);
                            });
                    }
                },
                'Usage: unquiet [USER_NAME]'
            ],
            kick: [
                {
                    pattern: /^(\S+)$/,
                    requires: 'operator',
                    execute: (event, target) => {
                        bot.users.get(target)
                            .then((whois) => {
                                if(bot.users.isInChannel(target, event.channel)){
                                    bot.giveOp(bot.client.nick, event.channel)
                                        .then(() => bot.kick(target, event.channel))
                                        .then(() => bot.takeOp(bot.client.nick, event.channel));
                                }else{
                                    throw ('User not in channel');
                                }

                            })
                            .then(() => {
                                bot.notify(event.nick, `${target} has been kicked.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not kick ${target}: ${error}`);
                            });
                    }
                },
                'Usage: kick [USER_NAME]'
            ]
        }
    };
};<commit_msg>Display length of quiet/op/voice<commit_after>'use strict';

var moment = require('moment');

module.exports = (bot, config) => {
    if (typeof config.data.timers === 'undefined') {
        config.data.timers = [];
    }
    const timers = config.data.timers;
    const actions = {
        deop: bot.takeOp,
        devoice: bot.takeVoice,
        unquiet: bot.takeQuiet
    };

    function addTimer(time, action, target, channel) {
        let timer = {
            time: time,
            action: action,
            target: target,
            channel: channel
        };
        timers.push(timer);
        setTimeout(executeTimer, moment(time).diff(moment()), timer);
        config.save();
    }

    function removeTimer(timer) {
        let location = timers.indexOf(timer);
        timers.splice(location, 1);
        config.save();
    }

    function executeTimer(timer) {
        try {
            actions[timer.action](timer.target, timer.channel);
            removeTimer(timer);
        } catch (e) {
            setTimeout(executeTimer, 10 * 1000, timer);
        }

    }

    function parseTime(args) {
        args = args.split(' ');

        for (let i = 0; i < args.length; i++) {
            if ((/^\d+$/).test(args[i])) {
                let unit = 'seconds';
                if ((/^\w+$/).test(args[i + 1])) unit = moment.normalizeUnits(args[i + 1]) || unit;
                return moment().add(args[i], unit);

            } else if (/^\d+\w$/.test(args[i])) {
                let time = args[i].replace(/[^\d]/gi, '');
                let unit = args[i].replace(/[\d]/gi, '');
                return moment().add(time, moment.normalizeUnits(unit));
            }
        }
    }

    // Load timers on plugin load
    for (let timer of timers) {
        let time = moment(timer.time).diff(moment());
        time = Math.max(time, 15 * 1000); // Timeout to make sure the bot is connected.
        setTimeout(executeTimer, time, timer);
    }

    return {
        commands: {
            op: [
                {
                    pattern: /^(\S*)$/,
                    requires: 'operator',
                    execute: (event, user) => {
                        if (user.length === 0) user = event.nick;
                        bot.giveOp(user, event.channel)
                            .then(() => {
                                bot.notify(event.nick, `User ${user} was opped.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not op user: ${error}`);
                            });
                    }
                },
                {
                    pattern: /^(\S*) (\S+) *(\S*)$/,
                    requires: 'operator',
                    execute: (event, user) => {
                        if (user.length === 0) user = event.nick;
                        const time = parseTime(event.args);
                        bot.giveOp(user, event.channel)
                            .then(() => {
                                addTimer(time, 'deop', user, event.channel);

                                bot.notify(event.nick, `User ${user} was opped for ${time.toNow(true)}.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not op user: ${error}`);
                            });
                    }
                },
                'Usage: op [USER_NAME] [TIME_STAMP]'
            ],
            deop: [
                {
                    pattern: /^(\S*)$/,
                    requires: 'operator',
                    execute: (event, user) => {
                        if (user.length === 0) user = event.nick;
                        bot.takeOp(user, event.channel)
                            .then(() => {
                                bot.notify(event.nick, `User ${user} was deopped.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not deop user: ${error}`);
                            });
                    }
                },
                'Usage: deop [USER_NAME]'
            ],
            voice: [
                {
                    pattern: /^(\S*)$/,
                    requires: 'operator',
                    execute: (event, user) => {
                        if (user.length === 0) user = event.nick;
                        bot.giveVoice(user, event.channel)
                            .then(() => {
                                bot.notify(event.nick, `User ${user} was voiced.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not voice user: ${error}`);
                            });
                    }
                },
                {
                    pattern: /^(\S*) (\S+) *(\S*)$/,
                    requires: 'operator',
                    execute: (event, user) => {
                        if (user.length === 0) user = event.nick;
                        const time = parseTime(event.args);
                        bot.giveVoice(user, event.channel)
                            .then(() => {
                                addTimer(time, 'devoice', user, event.channel);

                                bot.notify(event.nick, `User ${user} was voiced for ${time.toNow(true)}.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not voice user: ${error}`);
                            });
                    }
                },
                'Usage: voice [USER_NAME]'
            ],
            devoice: [
                {
                    pattern: /^(\S*)$/,
                    requires: 'operator',
                    execute: (event, user) => {
                        if (user.length === 0) user = event.nick;
                        bot.takeVoice(user, event.channel)
                            .then(() => {
                                bot.notify(event.nick, `User ${user} was devoiced.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not devoice user: ${error}`);
                            });
                    }
                },
                'Usage: devoice [USER_NAME]'
            ],
            quiet: [
                {
                    pattern: /^(\S+)$/,
                    requires: 'operator',
                    execute: (event, target) => {
                        bot.users.get(target)
                            .then((whois) => {
                                return bot.giveQuiet(`*!*@${whois.host}`, event.channel);
                            })
                            .then(() => {
                                bot.notify(event.nick, `${target} has been quieted.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not quiet ${target}: ${error}`);
                            });
                    }
                },
                {
                    pattern: /^(\S*) (\S+) *(\S*)$/,
                    requires: 'operator',
                    execute: (event, target) => {
                        const time = parseTime(event.args);
                        bot.users.get(target)
                            .then((whois) => {
                                addTimer(time, 'unquiet', `*!*@${whois.host}`, event.channel);

                                return bot.giveQuiet(`*!*@${whois.host}`, event.channel);
                            })
                            .then(() => {
                                bot.notify(event.nick, `${target} has been quieted for ${time.toNow(true)}.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not quiet ${target}: ${error}`);
                            });
                    }
                },
                'Usage: quiet [USER_NAME]'
            ],
            unquiet: [
                {
                    pattern: /^(\S+)$/,
                    requires: 'operator',
                    execute: (event, target) => {
                        bot.users.get(target)
                            .then((whois) => {
                                return bot.takeQuiet(`*!*@${whois.host}`, event.channel);
                            })
                            .then(() => {
                                bot.notify(event.nick, `${target} has been unquieted.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not unquiet ${target}: ${error}`);
                            });
                    }
                },
                'Usage: unquiet [USER_NAME]'
            ],
            kick: [
                {
                    pattern: /^(\S+)$/,
                    requires: 'operator',
                    execute: (event, target) => {
                        bot.users.get(target)
                            .then((whois) => {
                                if(bot.users.isInChannel(target, event.channel)){
                                    bot.giveOp(bot.client.nick, event.channel)
                                        .then(() => bot.kick(target, event.channel))
                                        .then(() => bot.takeOp(bot.client.nick, event.channel));
                                }else{
                                    throw ('User not in channel');
                                }

                            })
                            .then(() => {
                                bot.notify(event.nick, `${target} has been kicked.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not kick ${target}: ${error}`);
                            });
                    }
                },
                'Usage: kick [USER_NAME]'
            ]
        }
    };
};<|endoftext|>


<commit_before>import { A } from '@ember/array';
import Route from '@ember/routing/route';
import RSVP from 'rsvp';

import AuthenticatedRoute from '../mixins/authenticated-route';

export default Route.extend(AuthenticatedRoute, {
  setupController(controller) {
    this._super(...arguments);

    controller.set('myCrates', this.get('data.myCrates'));
    controller.set('myFollowing', this.get('data.myFollowing'));
    controller.set('myStats', this.get('data.myStats'));

    if (!controller.loadingMore) {
      controller.set('myFeed', A());
      controller.send('loadMore');
    }
  },

  model() {
    return this.get('session.currentUser');
  },

  async afterModel(user) {
    let myCrates = this.store.query('crate', {
      user_id: user.get('id'),
    });

    let myFollowing = this.store.query('crate', {
      following: 1,
    });

    let myStats = user.stats();

    this.set('data', await RSVP.hash({ myCrates, myFollowing, myStats }));
  },
});
<commit_msg>dashboard: Merge `model()` and `afterModel()` hook<commit_after>import { A } from '@ember/array';
import Route from '@ember/routing/route';
import RSVP from 'rsvp';

import AuthenticatedRoute from '../mixins/authenticated-route';

export default Route.extend(AuthenticatedRoute, {
  setupController(controller, model) {
    this._super(...arguments);

    controller.set('myCrates', model.myCrates);
    controller.set('myFollowing', model.myFollowing);
    controller.set('myStats', model.myStats);

    if (!controller.loadingMore) {
      controller.set('myFeed', A());
      controller.send('loadMore');
    }
  },

  async model() {
    let user = this.session.currentUser;

    let myCrates = this.store.query('crate', { user_id: user.get('id') });
    let myFollowing = this.store.query('crate', { following: 1 });
    let myStats = user.stats();

    return await RSVP.hash({ myCrates, myFollowing, myStats });
  },
});
<|endoftext|>


<commit_before>var request = require("request");

function SpacePeoplePlugin(bot) {
	var self = this;
	self.name = "spacepeople";
	self.help = "Howmanypeopelareinspacerightnow plugin";
	self.depend = ["cmd"];

	self.data = null;
	self.etag = null;

	self.events = {
		"cmd#peopleinspace": function(nick, to, args) {
			request({url: "http://www.howmanypeopleareinspacerightnow.com/peopleinspace.json", headers: (self.etag ? {"If-None-Match": self.etag} : {})}, function(err, res, body) {
				if (!err) {
					var data;
					if (res.statusCode == 200) {
						data = JSON.parse(body);
						self.data = data;
						self.etag = res.headers["etag"];
					}
					else if (res.statusCode == 304) {
						data = self.data;
					}

					bot.say(to, "People in space right now: " + data.number + " (" + data.people.map(function(person) { return person.name + " [" + person.country + "]"; }).join(", ") + ")");
				}
			});
		}
	}
}

module.exports = SpacePeoplePlugin;
<commit_msg>spacepeople: bold for important bits<commit_after>var request = require("request");

function SpacePeoplePlugin(bot) {
	var self = this;
	self.name = "spacepeople";
	self.help = "Howmanypeopelareinspacerightnow plugin";
	self.depend = ["cmd"];

	self.data = null;
	self.etag = null;

	self.events = {
		"cmd#peopleinspace": function(nick, to, args) {
			request({url: "http://www.howmanypeopleareinspacerightnow.com/peopleinspace.json", headers: (self.etag ? {"If-None-Match": self.etag} : {})}, function(err, res, body) {
				if (!err) {
					var data;
					if (res.statusCode == 200) {
						data = JSON.parse(body);
						self.data = data;
						self.etag = res.headers["etag"];
					}
					else if (res.statusCode == 304) {
						data = self.data;
					}

					bot.say(to, "People in space right now: \x02" + data.number + "\x02 (" + data.people.map(function(person) { return "\x02" + person.name + "\x02 [" + person.country + "]"; }).join(", ") + ")");
				}
			});
		}
	}
}

module.exports = SpacePeoplePlugin;
<|endoftext|>


<commit_before>import * as serializer from '../utils/serializer';
import InstancedItem from '../instanced-item';
import audio from '../audio';

const getFrame = (frames, number) => {
  let frame = frames[number];
  // Check if data is still a string:
  if (frame[0] === '[') {
    frame = frames[number] = JSON.parse(frame);
  }
  return frame;
};

const POSE = serializer.createPose();

export default class Frame {
  constructor(frames, seconds) {
    this.frames = frames;
    if (seconds !== undefined) {
      this.gotoTime(seconds);
    }
  }

  gotoTime(seconds, maxLayers) {
    this.time = seconds;
    this.maxLayers = maxLayers;
    this.needsUpdate = true;
  }

  secondsToFrame(seconds) {
    return (seconds % (audio.loopDuration * 2)) * this.frames.fps;
  }

  getHeadPose(index, offset, applyMatrix = true) {
    return this.getPose(index, 0, offset, applyMatrix);
  }

  getRHandPose(index, offset, applyMatrix = true) {
    return this.getPose(index, 1, offset, applyMatrix);
  }

  getLHandPose(index, offset, applyMatrix = true) {
    return this.getPose(index, 2, offset, applyMatrix);
  }

  get count() {
    if (this.needsUpdate) {
      this.update();
    }
    return this._count || 0;
  }

  update() {
    const { frames } = this.frames;
    const { time, maxLayers } = this;
    const frameCount = frames && frames.length;
    if (!frameCount) return;
    const frameNumber = Math.min(frameCount - 1, this.secondsToFrame(time));
    const lowerNumber = Math.floor(frameNumber);
    const higherNumber = Math.ceil(frameNumber);
    if (
      !frames ||
      frameCount <= higherNumber ||
      frameNumber === this.frameNumber
    ) return;
    this.frameNumber = frameNumber;
    const lower = this.lower = getFrame(frames, lowerNumber);
    this.higher = getFrame(frames, higherNumber);
    this.ratio = frameNumber % 1;
    this._count = maxLayers !== undefined
      ? Math.min(maxLayers, serializer.count(lower))
      : serializer.count(lower);
    this.needsUpdate = false;
  }

  getPose(performanceIndex, limbIndex, offset, applyMatrix, pose = POSE) {
    if (this.needsUpdate) this.update();
    const [position, quaternion] = pose;
    const { lower, higher, ratio } = this;
    serializer.avgPosition(
      lower,
      higher,
      ratio,
      performanceIndex,
      limbIndex,
      offset,
      position
    );
    if (applyMatrix) {
      position.applyMatrix4(InstancedItem.group.matrix);
    }
    serializer.avgQuaternion(
      lower,
      higher,
      ratio,
      performanceIndex,
      limbIndex,
      quaternion
    );
    return pose;
  }
}
<commit_msg>check for undefined as well as null<commit_after>import * as serializer from '../utils/serializer';
import InstancedItem from '../instanced-item';
import audio from '../audio';

const getFrame = (frames, number) => {
  let frame = frames[number];
  // Check if data is still a string:
  if (frame[0] === '[') {
    frame = frames[number] = JSON.parse(frame);
  }
  return frame;
};

const POSE = serializer.createPose();

export default class Frame {
  constructor(frames, seconds) {
    this.frames = frames;
    if (seconds !== undefined) {
      this.gotoTime(seconds);
    }
  }

  gotoTime(seconds, maxLayers) {
    this.time = seconds;
    this.maxLayers = maxLayers;
    this.needsUpdate = true;
  }

  secondsToFrame(seconds) {
    return (seconds % (audio.loopDuration * 2)) * this.frames.fps;
  }

  getHeadPose(index, offset, applyMatrix = true) {
    return this.getPose(index, 0, offset, applyMatrix);
  }

  getRHandPose(index, offset, applyMatrix = true) {
    return this.getPose(index, 1, offset, applyMatrix);
  }

  getLHandPose(index, offset, applyMatrix = true) {
    return this.getPose(index, 2, offset, applyMatrix);
  }

  get count() {
    if (this.needsUpdate) {
      this.update();
    }
    return this._count || 0;
  }

  update() {
    const { frames } = this.frames;
    const { time, maxLayers } = this;
    const frameCount = frames && frames.length;
    if (!frameCount) return;
    const frameNumber = Math.min(frameCount - 1, this.secondsToFrame(time));
    const lowerNumber = Math.floor(frameNumber);
    const higherNumber = Math.ceil(frameNumber);
    if (
      !frames ||
      frameCount <= higherNumber ||
      frameNumber === this.frameNumber
    ) return;
    this.frameNumber = frameNumber;
    const lower = this.lower = getFrame(frames, lowerNumber);
    this.higher = getFrame(frames, higherNumber);
    this.ratio = frameNumber % 1;
    this._count = maxLayers != null
      ? Math.min(maxLayers, serializer.count(lower))
      : serializer.count(lower);
    this.needsUpdate = false;
  }

  getPose(performanceIndex, limbIndex, offset, applyMatrix, pose = POSE) {
    if (this.needsUpdate) this.update();
    const [position, quaternion] = pose;
    const { lower, higher, ratio } = this;
    serializer.avgPosition(
      lower,
      higher,
      ratio,
      performanceIndex,
      limbIndex,
      offset,
      position
    );
    if (applyMatrix) {
      position.applyMatrix4(InstancedItem.group.matrix);
    }
    serializer.avgQuaternion(
      lower,
      higher,
      ratio,
      performanceIndex,
      limbIndex,
      quaternion
    );
    return pose;
  }
}
<|endoftext|>


<commit_before>'use strict';
var expect = require('expect.js');

describe('test', function () {
    it('should test', function () {
        expect(true).to.be(true);
    });
});
<commit_msg>Removed test test<commit_after><|endoftext|>


<commit_before>var toPull = require('stream-to-pull-stream')
var net = require('net')
var fs = require('fs')
var path = require('path')

// hax on double transform
var started = false

module.exports = function (opts) {
  const socket = path.join(opts.path || '', 'socket')
  const addr = 'unix:' + socket

  opts = opts || {}
  return {
    name: 'unix',
    scope: function() { return opts.scope || 'public' },
    server: function (onConnection) {
      if(started) return
      console.log("listening on socket", addr)

      var server = net.createServer(opts, function (stream) {
        onConnection(toPull.duplex(stream))
      }).listen(socket)

      server.on('error', function (e) {
        if (e.code == 'EADDRINUSE') {
          var clientSocket = new net.Socket()
          clientSocket.on('error', function(e) {
            if (e.code == 'ECONNREFUSED') {
              fs.unlinkSync(socket)
              server.listen(socket)
            }
          })

          clientSocket.connect({ path: socket }, function() {
            console.log("someone else is listening on socket!")
          })
        }
      })

      fs.chmodSync(socket, 0600)

      started = true

      return function () {
        server.close()
      }
    },
    client: function (opts, cb) {
      console.log("unix socket client")
      var started = false
      var stream = net.connect(opts)
        .on('connect', function () {
          if(started) return
          started = true

          cb(null, toPull.duplex(stream))
        })
        .on('error', function (err) {
          console.log("err?", err)
          if(started) return
          started = true
          cb(err)
        })

      return function () {
        started = true
        stream.destroy()
        cb(new Error('multiserver.unix: aborted'))
      }
    },
    //MUST be unix:socket_path
    parse: function (s) {
      var ary = s.split(':')
      if(ary.length < 2) return null
      if('unix' !== ary.shift()) return null
      return {
        name: '',
        path: ary.shift()
      }
    },
    stringify: function () {
      if(opts && !opts.server) return
      return ['unix', opts.path].join(':')
    }
  }
}

<commit_msg>Set address correctly on unix-socket.<commit_after>var toDuplex = require('stream-to-pull-stream').duplex
var net = require('net')
var fs = require('fs')
var path = require('path')

// hax on double transform
var started = false

module.exports = function (opts) {
  const socket = path.join(opts.path || '', 'socket')
  const addr = 'unix:' + socket

  opts = opts || {}
  return {
    name: 'unix',
    scope: function() { return opts.scope || 'public' },
    server: !opts.server ? null : function (onConnection) {
      if(started) return
      console.log("listening on socket", addr)

      var server = net.createServer(opts, function (stream) {
        stream = toDuplex(stream)
        stream.address = addr
        onConnection(stream)
      }).listen(socket)

      server.on('error', function (e) {
        if (e.code == 'EADDRINUSE') {
          var clientSocket = new net.Socket()
          clientSocket.on('error', function(e) {
            if (e.code == 'ECONNREFUSED') {
              fs.unlinkSync(socket)
              server.listen(socket)
            }
          })

          clientSocket.connect({ path: socket }, function() {
            console.log("someone else is listening on socket!")
          })
        }
      })

      fs.chmodSync(socket, 0600)

      started = true

      return function () {
        server.close()
      }
    },
    client: function (opts, cb) {
      console.log("unix socket client")
      var started = false
      var stream = net.connect(opts.path)
        .on('connect', function () {
          if(started) return
          started = true

          var _stream = toDuplex(stream)
          _stream.address = addr
          cb(null, _stream)
        })
        .on('error', function (err) {
          console.log("err?", err)
          if(started) return
          started = true
          cb(err)
        })

      return function () {
        started = true
        stream.destroy()
        cb(new Error('multiserver.unix: aborted'))
      }
    },
    //MUST be unix:socket_path
    parse: function (s) {
      var ary = s.split(':')
      if(ary.length < 2) return null
      if('unix' !== ary.shift()) return null
      return {
        name: '',
        path: ary.shift()
      }
    },
    stringify: function () {
      if(opts && !opts.server) return
      return ['unix', socket].join(':')
    }
  }
}

<|endoftext|>


<commit_before>window = {};
var assert = require('assert');
var model = require('../../lib/model')({
    memory: true,
    noConnect: true
});

describe('Model', function () {
    describe('interface', function () {
        it('should expose expected objects', function () {
            assert.equal(typeof model.data.history, 'object');
            assert.equal(typeof model.data.user, 'object');
            assert.equal(typeof model.data.apps, 'object');
        });

        it('should expose expected functions', function () {
            assert.equal(typeof model.restore, 'function');
            assert.equal(typeof model.save, 'function');
            assert.equal(typeof model.observe, 'function');
        });
    });

    describe('first run', function () {
        it('should have the expected history', function () {
            assert.deepEqual(model.data.history, {
                ftu: true,
                path: '/ftu'
            });
        });

        it('should have the expected user', function () {
            // @todo
            assert.deepEqual(model.data.user, {});
        });

        it('should have the expected apps', function () {
            // @todo
            assert.equal(model.data.apps.length, 0);
        });
    });
});
<commit_msg>fix tests<commit_after>window = {};
var assert = require('assert');
var model = require('../../lib/model')({
    memory: true,
    noConnect: true
});

describe('Model', function () {
    describe('interface', function () {
        it('should expose expected objects', function () {
            assert.equal(typeof model.data.history, 'object');
            assert.equal(typeof model.data.user, 'object');
            assert.equal(typeof model.data.apps, 'object');
        });

        it('should expose expected functions', function () {
            assert.equal(typeof model.restore, 'function');
            assert.equal(typeof model.save, 'function');
            assert.equal(typeof model.observe, 'function');
        });
    });

    describe('first run', function () {
        it('should have the expected history', function () {
            assert.deepEqual(model.data.history, {
                ftu: true,
                path: '/sign-in'
            });
        });

        it('should have the expected user', function () {
            // @todo
            assert.deepEqual(model.data.user, {});
        });

        it('should have the expected apps', function () {
            // @todo
            assert.equal(model.data.apps.length, 0);
        });
    });
});
<|endoftext|>


<commit_before>(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    define(['underscore', 'jquery', 'backbone', 'exports'], function(_, $, Backbone, exports) {
      root.Paradocs = factory(root, exports, Backbone, _, $);
    });
  } else {
    root.Paradocs = factory(root, {}, root.Backbone, root._, (root.jQuery || root.$));
  }
}(this, function(root, Paradocs, Backbone, _, $){
  Paradocs.VERSION = 0.5;

  var DocsModel = Backbone.Model.extend({});
  var AppRouter = Backbone.Router.extend({
    routes: {"docs/*tech": 'docs'},
    docs: function(filepath){ Paradocs.fetch(filepath) }
  });
  Paradocs.fetch = function (filepath) {
    $.ajax({
      headers: {Accept : "application/vnd.github.VERSION.html+json"},
      url: "https://api.github.com/repos/tsironis/dockie/contents/"+filepath+".md",
      type: "GET",
    }).done(function(html) {
      Paradocs.save(html, filepath);
    });
  };
  Paradocs.populateNavItems = function(html) {
    return _.map($('h2', html), function(el) {
      return '
'+$(el).text()+'
';
    }).join('');
  };
  /* Saves text in a Model for future use */
  Paradocs.save = function(html, filepath) {
    this._data.set({
      'text': html,
      'nav' : this.populateNavItems(html)
    });
  };
  Paradocs.get = function (key) {
    return this._data.get(key);
  };

  Paradocs._data = new DocsModel();
  Paradocs.router = new AppRouter();
  Backbone.history.start();

  return Paradocs;
}));
<commit_msg>Cleaning up<commit_after>(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    define(['underscore', 'jquery', 'backbone', 'exports'], function(_, $, Backbone, exports) {
      root.Paradocs = factory(root, exports, Backbone, _, $);
    });
  } else {
    root.Paradocs = factory(root, {}, root.Backbone, root._, (root.jQuery || root.$));
  }
}(this, function(root, Paradocs, Backbone, _, $) {
  Paradocs.VERSION = 0.5;

  var DocsModel = Backbone.Model.extend({});
  var AppRouter = Backbone.Router.extend({
    routes: {"docs/*tech": 'docs'},
    docs: function(filepath){ Paradocs.fetch(filepath) }
  });
  Paradocs.fetch = function (filepath) {
    $.ajax({
      headers: {Accept : "application/vnd.github.VERSION.html+json"},
      url: "https://api.github.com/repos/tsironis/dockie/contents/"+filepath+".md",
      type: "GET",
    }).done(function(html) {
      Paradocs.save(html, filepath);
    });
  };
  Paradocs.populateNavItems = function(html) {
    return _.map($('h2', html), function(el) {
      return '
'+$(el).text()+'
';
    }).join('');
  };
  /* Saves text in a Model for future use */
  Paradocs.save = function(html) {
    this._data.set({
      'text': html,
      'nav' : this.populateNavItems(html)
    });
  };
  Paradocs.get = function (key) {
    return this._data.get(key);
  };

  Paradocs._data = new DocsModel();
  Paradocs.router = new AppRouter();
  Backbone.history.start();

  return Paradocs;
}));
<|endoftext|>


<commit_before>'use strict';

exports.run = function(app) {
	var routes = require('./routes/index');

	app.get('/', routes.index);

	app.get('/queries', routes.queries.list);
	app.get('/queries/:query', routes.queries.show);
	app.post('/queries/:query', routes.queries.create);
	app.delete('/queries/:query', routes.queries.delete);
	app.get('/queries/:query/results', routes.queries.showResults);

	// TODO: https://github.com/JeroenDeDauw/BeyondWikidata/blob/master/ApiSpec.md
};<commit_msg>Add routes from API spec<commit_after>'use strict';

exports.run = function(app) {
	var routes = require('./routes/index');

	app.get('/', routes.index);

	app.get('/queries', routes.queries.list);
	app.get('/queries/:query', routes.queries.show);
	app.post('/queries/:query', routes.queries.create);
	app.delete('/queries/:query', routes.queries.delete);
	app.get('/queries/:query/results', routes.queries.showResults);

	app.get('/results', routes.results.list);
	app.get('/results/:result', routes.results.show);
	app.delete('/results/:result', routes.results.delete);

	app.post('/run', routes.run.run);
	app.post('/run/:query', routes.run.runQuery);

	app.get('/users/:user', routes.users.listPrivateQueries);
	app.get('/users/:user/queries', routes.users.listPrivateQueries);
	app.get('/users/:user/queries/public', routes.users.listPublicQueries);
	app.get('/users/:user/results', routes.users.listPrivateResults);
	app.get('/users/:user/results/public', routes.users.listPublicResults);

	// TODO: https://github.com/JeroenDeDauw/BeyondWikidata/blob/master/ApiSpec.md
};<|endoftext|>


<commit_before>import * as world from './utils/world.js'

const offsetX = 27
const offsetY = 12
const initialWorld = [
  [1, 2], [2, 1], [2, 2], [2, 3], [3, 3]
].map(([x, y]) => [x + offsetX, y + offsetY])

const CELLS_X = 60
const CELLS_Y = 30

const initialState = {
  world: initialWorld,
  size: [CELLS_X, CELLS_Y]
}

const addCell = (state, {x, y}) => {
  const newWorld = world.addCell(state.world, x, y)

  return Object.assign({}, state, {world: newWorld})
}

const removeCell = (state, {x, y}) => {
  const newWorld = world.removeCell(state.world, x, y)

  return Object.assign({}, state, {world: newWorld})
}

const toggleCell = (state, action) => {
  let cellExists = world.getCell(state.world, action.x, action.y)

  return cellExists ? removeCell(state, action) : addCell(state, action)
}

const tick = (state, action) => {
  let newWorld = world.tick(state.world || [])
  const [maxX, maxY] = state.size
  newWorld = world.clamp(newWorld, 0, maxX, 0, maxY)

  return Object.assign({}, state, {world: newWorld})
}

const clearWorld = (state, action) => {
  return Object.assign({}, state, {world: [], timerRunning: false})
}

const toggleTimer = (state, action) => {
  return state.timerRunning ? stopTimer(state, action) : startTimer(state, action)
}

const startTimer = (state, action) => {
  return Object.assign({}, state, {timerRunning: true})
}

const stopTimer = (state, action) => {
  return Object.assign({}, state, {timerRunning: false})
}

const reducers = (state = initialState, action) => {
  console.log('DISPATCHING', action)
  switch (action.type) {
    case 'ADD_CELL': return addCell(state, action)
    case 'REMOVE_CELL': return removeCell(state, action)
    case 'TOGGLE_CELL': return toggleCell(state, action)
    case 'TICK': return tick(state, action)
    case 'CLEAR_WORLD': return clearWorld(state, action)
    case 'START_TIMER': return startTimer(state, action)
    case 'STOP_TIMER': return stopTimer(state, action)
    case 'TOGGLE_TIMER': return toggleTimer(state, action)
    default: return state
  }
}

export default reducers
<commit_msg>state: stop timer when world is empty<commit_after>import * as world from './utils/world.js'

const offsetX = 27
const offsetY = 12
const initialWorld = [
  [1, 2], [2, 1], [2, 2], [2, 3], [3, 3]
].map(([x, y]) => [x + offsetX, y + offsetY])

const CELLS_X = 60
const CELLS_Y = 30

const initialState = {
  world: initialWorld,
  size: [CELLS_X, CELLS_Y]
}

const addCell = (state, {x, y}) => {
  const newWorld = world.addCell(state.world, x, y)

  return Object.assign({}, state, {world: newWorld})
}

const removeCell = (state, {x, y}) => {
  const newWorld = world.removeCell(state.world, x, y)

  return Object.assign({}, state, {world: newWorld})
}

const toggleCell = (state, action) => {
  let cellExists = world.getCell(state.world, action.x, action.y)

  return cellExists ? removeCell(state, action) : addCell(state, action)
}

const tick = (state, action) => {
  let newWorld = world.tick(state.world || [])
  const [maxX, maxY] = state.size
  newWorld = world.clamp(newWorld, 0, maxX, 0, maxY)

  const worldEmpty = newWorld.length === 0
  const timerRunning = worldEmpty ? false : state.timerRunning

  return Object.assign({}, state, {world: newWorld, timerRunning})
}

const clearWorld = (state, action) => {
  return Object.assign({}, state, {world: [], timerRunning: false})
}

const toggleTimer = (state, action) => {
  return state.timerRunning ? stopTimer(state, action) : startTimer(state, action)
}

const startTimer = (state, action) => {
  return Object.assign({}, state, {timerRunning: true})
}

const stopTimer = (state, action) => {
  return Object.assign({}, state, {timerRunning: false})
}

const reducers = (state = initialState, action) => {
  console.log('DISPATCHING', action)
  switch (action.type) {
    case 'ADD_CELL': return addCell(state, action)
    case 'REMOVE_CELL': return removeCell(state, action)
    case 'TOGGLE_CELL': return toggleCell(state, action)
    case 'TICK': return tick(state, action)
    case 'CLEAR_WORLD': return clearWorld(state, action)
    case 'START_TIMER': return startTimer(state, action)
    case 'STOP_TIMER': return stopTimer(state, action)
    case 'TOGGLE_TIMER': return toggleTimer(state, action)
    default: return state
  }
}

export default reducers
<|endoftext|>


<commit_before>(function () {

  /* @ngInject */
  angular
    .module('app.services', ['ngResource'])
    .constant('BaseUrl', 'http://localhost:3000')
    .factory('Week', Week)
    .factory('Days', Days)
    .factory('Day', Day)
    .factory('DayToggleWr', DayToggleWr)
    .factory('Ods', Ods)
    .factory('OdToggleO', OdToggleO)
    .factory('OdToggleD', OdToggleD)
    .factory('Page', Page);

  /* @ngInject */
  function Week ($resource, BaseUrl) {
    return $resource(BaseUrl + '/weeks/:id.json',
      { id: '@_id' }
    );
  }

  /* @ngInject */
  function Days ($resource, BaseUrl) {
    return $resource(BaseUrl + '/weeks/:id/days.json',
      { id: '@_id' }
    );
  }

  /* @ngInject */
  function Day ($resource, BaseUrl) {
    return $resource(BaseUrl + '/days/:id.json',
      { id: '@_id' }
    );
  }

  /* @ngInject */
  function DayToggleWr ($resource, BaseUrl) {
    return $resource(BaseUrl + '/days/:id/toggle_wr.json',
      { id: '@id' }, {
        toggleWr: {method:'PATCH'}
      }
    );
  }

  /* @ngInject */
  function Ods ($resource, BaseUrl) {
    return $resource(BaseUrl + '/days/:id/ods.json',
      { id: '@_id' }
    );
  }

  /* @ngInject */
  function OdToggleO ($resource, BaseUrl) {
    return $resource(BaseUrl + '/ods/:id/toggle_o.json',
      { id: '@id' }, {
        toggle_o: {method:'PATCH'}
      }
    );
  }

  /* @ngInject */
  function OdToggleD ($resource, BaseUrl) {
    return $resource(BaseUrl + '/ods/:id/toggle_d.json',
      { id: '@id' }, {
        toggle_d: {method:'PATCH'}
      }
    );
  }

  function Page() {
    var title = 'pnp Anglais';
    return {
      title: function() { return title; },
      setTitle: function(newTitle) { title = newTitle; }
    };
  }

})();
<commit_msg>removes helper services to own file<commit_after>(function () {

  /* @ngInject */
  angular
    .module('app.services', ['ngResource'])
    .constant('BaseUrl', 'http://localhost:3000')
    .factory('Week', Week)
    .factory('Days', Days)
    .factory('Day', Day)
    .factory('DayToggleWr', DayToggleWr)
    .factory('Ods', Ods)
    .factory('OdToggleO', OdToggleO)
    .factory('OdToggleD', OdToggleD);

  /* @ngInject */
  function Week ($resource, BaseUrl) {
    return $resource(BaseUrl + '/weeks/:id.json',
      { id: '@_id' }
    );
  }

  /* @ngInject */
  function Days ($resource, BaseUrl) {
    return $resource(BaseUrl + '/weeks/:id/days.json',
      { id: '@_id' }
    );
  }

  /* @ngInject */
  function Day ($resource, BaseUrl) {
    return $resource(BaseUrl + '/days/:id.json',
      { id: '@_id' }
    );
  }

  /* @ngInject */
  function DayToggleWr ($resource, BaseUrl) {
    return $resource(BaseUrl + '/days/:id/toggle_wr.json',
      { id: '@id' }, {
        toggleWr: {method:'PATCH'}
      }
    );
  }

  /* @ngInject */
  function Ods ($resource, BaseUrl) {
    return $resource(BaseUrl + '/days/:id/ods.json',
      { id: '@_id' }
    );
  }

  /* @ngInject */
  function OdToggleO ($resource, BaseUrl) {
    return $resource(BaseUrl + '/ods/:id/toggle_o.json',
      { id: '@id' }, {
        toggle_o: {method:'PATCH'}
      }
    );
  }

  /* @ngInject */
  function OdToggleD ($resource, BaseUrl) {
    return $resource(BaseUrl + '/ods/:id/toggle_d.json',
      { id: '@id' }, {
        toggle_d: {method:'PATCH'}
      }
    );
  }

})();
<|endoftext|>


<commit_before>import test from 'ava'
const utils = require('../lib/utils')

test('encodeHtml', t => {
  const html = '
Hello
'
  t.is(utils.encodeHtml(html), '<h1>Hello</h1>')
})

test('getContext', t => {
  let ctx = utils.getContext({ a: 1 }, { b: 2 })
  t.is(utils.getContext.length, 2)
  t.is(typeof ctx.req, 'object')
  t.is(typeof ctx.res, 'object')
  t.is(ctx.req.a, 1)
  t.is(ctx.res.b, 2)
})
<commit_msg>Add tests for utils<commit_after>import test from 'ava'
const utils = require('../lib/utils')

test('encodeHtml', t => {
  const html = '
Hello
'
  t.is(utils.encodeHtml(html), '<h1>Hello</h1>')
})

test('getContext', t => {
  let ctx = utils.getContext({ a: 1 }, { b: 2 })
  t.is(utils.getContext.length, 2)
  t.is(typeof ctx.req, 'object')
  t.is(typeof ctx.res, 'object')
  t.is(ctx.req.a, 1)
  t.is(ctx.res.b, 2)
})

test('waitFor', function * (t) {
  let s = Date.now()
  yield utils.waitFor(100)
  t.true(Date.now() - s >= 100)
})

test('urlJoin', t => {
  t.is(utils.urlJoin('test', '/about'), 'test/about')
})

test('promisifyRouteParams (array)', t => {
  const array = [1]
  const promise = utils.promisifyRouteParams(array)
  t.true(promise instanceof Promise)
  return promise
  .then((res) => {
    t.is(res, array)
  })
})

test('promisifyRouteParams (fn => array)', t => {
  const array = [1, 2]
  const fn = function () {
    return array
  }
  const promise = utils.promisifyRouteParams(fn)
  t.true(promise instanceof Promise)
  return promise
  .then((res) => {
    t.is(res, array)
  })
})

test('promisifyRouteParams (fn => promise)', t => {
  const array = [1, 2, 3]
  const fn = function () {
    return new Promise((resolve) => {
      resolve(array)
    })
  }
  const promise = utils.promisifyRouteParams(fn)
  t.true(promise instanceof Promise)
  return promise
  .then((res) => {
    t.is(res, array)
  })
})

test('promisifyRouteParams (fn(cb) with error)', t => {
  const fn = function (cb) {
    cb('Error here')
  }
  const promise = utils.promisifyRouteParams(fn)
  t.true(promise instanceof Promise)
  return promise
  .catch((e) => {
    t.is(e, 'Error here')
  })
})

test('promisifyRouteParams (fn(cb) with result)', t => {
  const array = [1, 2, 3, 4]
  const fn = function (cb) {
    cb(null, array)
  }
  const promise = utils.promisifyRouteParams(fn)
  t.true(promise instanceof Promise)
  return promise
  .then((res) => {
    t.is(res, array)
  })
})
<|endoftext|>


<commit_before>export class StorageService {
  constructor () {
    this.keys = {
      databaseName: 'oh-hell',
      storeName: 'oh-hell',
      games: 'games',
      settings: 'settings',
    };

    localforage.config({
      driver: localforage.WEBSQL,
      name: this.keys.databaseName,
      version: 1.0,
      size: 4980736,
      storeName: this.keys.storeName,
      description: 'Oh Hell Game Storage'
    });

    this.games = localforage.createInstance({name: this.keys.games});
    this.settings = localforage.createInstance({name: this.keys.settings});
  }

  /** Games */

  getAllGames () {
    return this.games.getItem(this.keys.games);
  }

  getLatestGame () {
    return new Promise((resolve, reject) => {
      this.getAllGames().then((games) => {
        if (!games) {
          return resolve(null);
        }

        resolve(games[games.length - 1]);
      }, reject);
    });
  }

  saveGame (game) {
    return new Promise((resolve, reject) => {
      this.getAllGames().then((games) => {
        if (!games) {
          games = [];
          games.push(game);
          return this.games.setItem(this.keys.games, games).then(resolve, reject);
        }

        this.findGameIndex(game).then((index) => {
          if (index === -1) {
            games.push(game);
          } else {
            games[index] = game;
          }

          games = _.sortBy(games, 'startTime');

          this.games.setItem(this.keys.games, games).then(resolve, reject);
        }, reject);
      }, reject);
    });
  }

  findGameIndex (game) {
    return new Promise((resolve, reject) => {
      if (!game) {
        return reject(null);
      }

      this.getAllGames().then((games) => {
        resolve(_.findIndex(games, {id: game.id}));
      }, reject);
    });
  }

  findGameById (id) {
    return new Promise((resolve, reject) => {
      if (!id) {
        return reject(null);
      }

      this.getAllGames().then((games) => {
        resolve(_.find(games, {id: id}));
      }, reject);
    });
  }

  deleteGame (game) {
    return new Promise((resolve, reject) => {
      this.getAllGames().then((games) => {
        _.remove(games, {id: game.id});
        this.games.setItem(this.keys.games, games).then(resolve, reject);
      }, reject);
    });
  }

  /** Settings */

  saveSettings (settings) {
    this.settings.setItem(this.keys.settings, settings);
  }

  getSettings () {
    return this.settings.getItem(this.keys.settings);
  }
}
<commit_msg>Don't save an invalid game<commit_after>export class StorageService {
  constructor () {
    this.keys = {
      databaseName: 'oh-hell',
      storeName: 'oh-hell',
      games: 'games',
      settings: 'settings',
    };

    localforage.config({
      driver: localforage.WEBSQL,
      name: this.keys.databaseName,
      version: 1.0,
      size: 4980736,
      storeName: this.keys.storeName,
      description: 'Oh Hell Game Storage'
    });

    this.games = localforage.createInstance({name: this.keys.games});
    this.settings = localforage.createInstance({name: this.keys.settings});
  }

  /** Games */

  getAllGames () {
    return this.games.getItem(this.keys.games);
  }

  getLatestGame () {
    return new Promise((resolve, reject) => {
      this.getAllGames().then((games) => {
        if (!games) {
          return resolve(null);
        }

        resolve(games[games.length - 1]);
      }, reject);
    });
  }

  saveGame (game) {
    return new Promise((resolve, reject) => {
      if (!game) {
        return reject(null);
      }

      this.getAllGames().then((games) => {
        if (!games) {
          games = [];
          games.push(game);
          return this.games.setItem(this.keys.games, games).then(resolve, reject);
        }

        this.findGameIndex(game).then((index) => {
          if (index === -1) {
            games.push(game);
          } else {
            games[index] = game;
          }

          games = _.sortBy(games, 'startTime');

          this.games.setItem(this.keys.games, games).then(resolve, reject);
        }, reject);
      }, reject);
    });
  }

  findGameIndex (game) {
    return new Promise((resolve, reject) => {
      if (!game) {
        return reject(null);
      }

      this.getAllGames().then((games) => {
        resolve(_.findIndex(games, {id: game.id}));
      }, reject);
    });
  }

  findGameById (id) {
    return new Promise((resolve, reject) => {
      if (!id) {
        return reject(null);
      }

      this.getAllGames().then((games) => {
        resolve(_.find(games, {id: id}));
      }, reject);
    });
  }

  deleteGame (game) {
    return new Promise((resolve, reject) => {
      this.getAllGames().then((games) => {
        _.remove(games, {id: game.id});
        this.games.setItem(this.keys.games, games).then(resolve, reject);
      }, reject);
    });
  }

  /** Settings */

  saveSettings (settings) {
    this.settings.setItem(this.keys.settings, settings);
  }

  getSettings () {
    return this.settings.getItem(this.keys.settings);
  }
}
<|endoftext|>


<commit_before>var assert = require('assert'),
  moment = require('moment');

describe("go.utils", function() {

  beforeEach(function() {
    // patch the date we're working with in tests.
    go.utils.get_current_date = function() {
      return moment.utc('2014-09-01T00:00:00+00:00').toDate();
    };
  });

  it('should calculate the week of year when given a month in this year', function() {
    // December, still in 2014
    assert.equal(
      go.utils.month_of_year_to_week('11').toISOString(),
      '2014-12-15T00:00:00.000Z');
  });

  it('should calculate the week of year when given a month in next year', function() {
    // January, should roll over into 2015
    assert.equal(
      go.utils.month_of_year_to_week('0').toISOString(),
      '2015-01-15T00:00:00.000Z');
  });

  it('should calculate the week of year when given a month in past year', function() {
    // May should roll over into 2015
    assert.equal(
      go.utils.month_of_year_to_week('4').getFullYear(), 2015);
    // June should still be 2014
    assert.equal(
      go.utils.month_of_year_to_week('5').getFullYear(), 2014);

  });

  it('should calculate the week when given a month', function () {
    // this turns the 'how many months old is your baby' question
    // into how many weeks old the baby already is.
    // NOTE: the calculation is pretty rough as we're assuming 4 weeks
    //     in a month
    assert.equal(
      go.utils.months_to_week(1).toISOString(),
      '2014-08-25T00:00:00.000Z');
    assert.equal(
      go.utils.months_to_week(12).toISOString(),
      '2013-10-21T00:00:00.000Z');
  });

  it('should return today\'s date as a string', function () {
    assert.equal(
      go.utils.get_today_as_string(),
      '2014-09-01');
  });
  it('should return a holodeck compatible timestamp', function () {
    assert.equal(
      go.utils.get_holodeck_timestamp(),
      '2014-09-01 00:00:00');
  });
  it('should calculate when last monday was on monday', function () {
    assert.equal(
      go.utils.get_last_monday().toISOString(),
      '2014-08-25T00:00:00.000Z');
  });
  it('should calculate when last monday was on a not monday', function () {
    assert.equal(
      go.utils.get_last_monday(
        moment.utc('2014-09-02T00:00:00+00:00').toDate()).toISOString(),
      '2014-09-01T00:00:00.000Z');
  });
  it('should return the week number when given birth date is today', function () {
    assert.equal(
      go.utils.calculate_weeks_remaining(
        moment.utc('2014-09-01T00:00:00.000Z').toDate()),
      1);
  });
  it('should return the week number when given birth date 9 months away', function () {
    assert.equal(
      go.utils.calculate_weeks_remaining(
        moment.utc('2015-06-01T00:00:00.000Z').toDate()),
      40);
  });
  it('should return the week number when given birth date 3 months away', function () {
    assert.equal(
      go.utils.calculate_weeks_remaining(
        moment.utc('2014-12-01T00:00:00.000Z').toDate()),
      14);
  });
  it('should return the week number when given birth date 6 months away', function () {
    assert.equal(
      go.utils.calculate_weeks_remaining(
        moment.utc('2015-03-01T00:00:00.000Z').toDate()),
      26);
  });
  it('should return the week number when given a past birth date', function () {
    assert.equal(
      go.utils.calculate_weeks_remaining(
        moment.utc('2014-08-18T00:00:00.000Z').toDate()),
      -1);
  });
  it('should return a "poll number" for a birth date', function () {
    assert.equal(
      go.utils.get_poll_number(
        moment.utc('2014-11-15T00:00:00.000Z').toDate()),
      25);
  });
  it('should provide a helper function for getting the seq-send keys');
  it('should provide a helper for sending an SMS');
});
<commit_msg>remove obsolete tests<commit_after>var assert = require('assert'),
  moment = require('moment');

describe("go.utils", function() {

  beforeEach(function() {
    // patch the date we're working with in tests.
    go.utils.get_current_date = function() {
      return moment.utc('2014-09-01T00:00:00+00:00').toDate();
    };
  });

  it('should calculate the week of year when given a month in this year', function() {
    // December, still in 2014
    assert.equal(
      go.utils.month_of_year_to_week('11').toISOString(),
      '2014-12-15T00:00:00.000Z');
  });

  it('should calculate the week of year when given a month in next year', function() {
    // January, should roll over into 2015
    assert.equal(
      go.utils.month_of_year_to_week('0').toISOString(),
      '2015-01-15T00:00:00.000Z');
  });

  it('should calculate the week of year when given a month in past year', function() {
    // May should roll over into 2015
    assert.equal(
      go.utils.month_of_year_to_week('4').getFullYear(), 2015);
    // June should still be 2014
    assert.equal(
      go.utils.month_of_year_to_week('5').getFullYear(), 2014);

  });

  it('should calculate the week when given a month', function () {
    // this turns the 'how many months old is your baby' question
    // into how many weeks old the baby already is.
    // NOTE: the calculation is pretty rough as we're assuming 4 weeks
    //     in a month
    assert.equal(
      go.utils.months_to_week(1).toISOString(),
      '2014-08-25T00:00:00.000Z');
    assert.equal(
      go.utils.months_to_week(12).toISOString(),
      '2013-10-21T00:00:00.000Z');
  });

  it('should return today\'s date as a string', function () {
    assert.equal(
      go.utils.get_today_as_string(),
      '2014-09-01');
  });
  it('should return a holodeck compatible timestamp', function () {
    assert.equal(
      go.utils.get_holodeck_timestamp(),
      '2014-09-01 00:00:00');
  });
  it('should calculate when last monday was on monday', function () {
    assert.equal(
      go.utils.get_last_monday().toISOString(),
      '2014-08-25T00:00:00.000Z');
  });
  it('should calculate when last monday was on a not monday', function () {
    assert.equal(
      go.utils.get_last_monday(
        moment.utc('2014-09-02T00:00:00+00:00').toDate()).toISOString(),
      '2014-09-01T00:00:00.000Z');
  });
  it('should return the week number when given birth date is today', function () {
    assert.equal(
      go.utils.calculate_weeks_remaining(
        moment.utc('2014-09-01T00:00:00.000Z').toDate()),
      1);
  });
  it('should return the week number when given birth date 9 months away', function () {
    assert.equal(
      go.utils.calculate_weeks_remaining(
        moment.utc('2015-06-01T00:00:00.000Z').toDate()),
      40);
  });
  it('should return the week number when given birth date 3 months away', function () {
    assert.equal(
      go.utils.calculate_weeks_remaining(
        moment.utc('2014-12-01T00:00:00.000Z').toDate()),
      14);
  });
  it('should return the week number when given birth date 6 months away', function () {
    assert.equal(
      go.utils.calculate_weeks_remaining(
        moment.utc('2015-03-01T00:00:00.000Z').toDate()),
      26);
  });
  it('should return the week number when given a past birth date', function () {
    assert.equal(
      go.utils.calculate_weeks_remaining(
        moment.utc('2014-08-18T00:00:00.000Z').toDate()),
      -1);
  });
  it('should return a "poll number" for a birth date', function () {
    assert.equal(
      go.utils.get_poll_number(
        moment.utc('2014-11-15T00:00:00.000Z').toDate()),
      25);
  });
});
<|endoftext|>


<commit_before>/*
* Copyright (C) 2015-2016 by Arena of Titans Contributors.
*
* This file is part of Arena of Titans.
*
* Arena of Titans is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Arena of Titans is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Arena of Titans. If not, see <http://www.gnu.org/licenses/>.
*/

const OPTIONS_KEY = 'options';
const PLAYER_INFOS_KEY = 'player';
const KEEP_PLAYER_ID_DURATION = 7 * 24 * 60 * 60 * 1000;

export class Storage {
    _expiresKey = 'expires';

    savePlayerId(gameId, playerId) {
        for (let key of Object.keys(localStorage)) {
            if (key !== OPTIONS_KEY && key !== PLAYER_INFOS_KEY) {
                let data = localStorage.getItem(key);
                // Convert old keys to new format with the date.
                // TODO: remove this part after some time.
                try {
                    // If we can parse the JSON, then the value is in the new format.
                    data = JSON.parse(data);
                } catch (e) {
                    data = {
                        playerId: playerId,
                        date: Date.now(),
                    };
                    localStorage.setItem(key, JSON.stringify(data));
                }

                // Remove old keys.
                if ((Date.now() - data.date) > KEEP_PLAYER_ID_DURATION) {
                    localStorage.removeItem(key);
                }
            }
        }

        let data = {
            playerId: playerId,
            date: Date.now(),
        };
        localStorage.setItem(gameId, JSON.stringify(data));
    }

    retrievePlayerId(gameId) {
        let data = localStorage.getItem(gameId);
        data = JSON.parse(data);

        return data.playerId;
    }

    saveOptions(options) {
        let toSave = {};
        // We don't save private properties
        for (let key of Object.keys(options)) {
            if (!key.startsWith('_')) {
                toSave[key] = options[key];
            }
        }
        localStorage.setItem(OPTIONS_KEY, JSON.stringify(toSave));
    }

    loadOptions() {
        return JSON.parse(localStorage.getItem(OPTIONS_KEY)) || {};
    }

    savePlayerInfos(infos) {
        localStorage.setItem(PLAYER_INFOS_KEY, JSON.stringify(infos));
    }

    loadPlayerInfos() {
        return JSON.parse(localStorage.getItem(PLAYER_INFOS_KEY)) || {name: '', hero: ''};
    }
}
<commit_msg>fix(storage): prevent access to property of null<commit_after>/*
* Copyright (C) 2015-2016 by Arena of Titans Contributors.
*
* This file is part of Arena of Titans.
*
* Arena of Titans is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Arena of Titans is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Arena of Titans. If not, see <http://www.gnu.org/licenses/>.
*/

const OPTIONS_KEY = 'options';
const PLAYER_INFOS_KEY = 'player';
const KEEP_PLAYER_ID_DURATION = 7 * 24 * 60 * 60 * 1000;

export class Storage {
    _expiresKey = 'expires';

    savePlayerId(gameId, playerId) {
        for (let key of Object.keys(localStorage)) {
            if (key !== OPTIONS_KEY && key !== PLAYER_INFOS_KEY) {
                let data = localStorage.getItem(key);
                // Convert old keys to new format with the date.
                // TODO: remove this part after some time.
                try {
                    // If we can parse the JSON, then the value is in the new format.
                    data = JSON.parse(data);
                } catch (e) {
                    data = {
                        playerId: playerId,
                        date: Date.now(),
                    };
                    localStorage.setItem(key, JSON.stringify(data));
                }

                // Remove old keys.
                if ((Date.now() - data.date) > KEEP_PLAYER_ID_DURATION) {
                    localStorage.removeItem(key);
                }
            }
        }

        let data = {
            playerId: playerId,
            date: Date.now(),
        };
        localStorage.setItem(gameId, JSON.stringify(data));
    }

    retrievePlayerId(gameId) {
        let data = localStorage.getItem(gameId);
        data = JSON.parse(data);

        return data === null ? data : data.playerId;
    }

    saveOptions(options) {
        let toSave = {};
        // We don't save private properties
        for (let key of Object.keys(options)) {
            if (!key.startsWith('_')) {
                toSave[key] = options[key];
            }
        }
        localStorage.setItem(OPTIONS_KEY, JSON.stringify(toSave));
    }

    loadOptions() {
        return JSON.parse(localStorage.getItem(OPTIONS_KEY)) || {};
    }

    savePlayerInfos(infos) {
        localStorage.setItem(PLAYER_INFOS_KEY, JSON.stringify(infos));
    }

    loadPlayerInfos() {
        return JSON.parse(localStorage.getItem(PLAYER_INFOS_KEY)) || {name: '', hero: ''};
    }
}
<|endoftext|>


<commit_before>'use strict'

const assert = require('chai').assert
const uuid = require('uuid/v4')
const link = require('../../src/utils/link')
const filename = require('../../src/utils/filename')

describe('link()', function() {

	it('should work with an empty data string', function() {

		const html = ''
		const components = []
		const render = () => ''

		const result = link(html, components, render)

		assert.strictEqual(result, html)

	})

	it('should replace names with links', function() {

		const components = [
			{
				// Component with a long path
				id: uuid(),
				src: `${ uuid() }/${ uuid() }/_${ uuid() }.njk`
			},
			{
				// Component with a path
				id: uuid(),
				src: `${ uuid() }/${ uuid() }.njk`
			},
			{
				// Component without a filename only
				id: uuid(),
				src: `${ uuid() }.njk`
			}
		]

		// Component with a name that includes the name of another component
		components.push({
			id: uuid(),
			src: uuid() + components[2].src
		})

		// Unused component
		components.push({
			id: uuid(),
			src: `${ uuid() }.njk`
		})

		const html = `
			${ components[0].src }
			{% inject "${ components[1].src }" %}
			${ components[2].src }
			${ components[3].src }
		`

		// The real renderer gets a safe filename from the link function
		const realRender = (component, filename) => filename

		// The fake renderer needs to escape the filename like the link function does
		const fakeRender = (filename) => [ ...filename ].map((char) => `<span>${ char }</span>`).join('')

		// Removes the filename from a path
		const pathWithoutFilename = (src) => src.replace(filename(src), '')

		const expected = `
			${ pathWithoutFilename(components[0].src) + fakeRender(filename(components[0].src)) }
			{% inject "${ pathWithoutFilename(components[1].src) + fakeRender(filename(components[1].src)) }" %}
			${ fakeRender(filename(components[2].src)) }
			${ fakeRender(filename(components[3].src)) }
		`

		const result = link(html, components, realRender)

		assert.strictEqual(result, expected)

	})

})<commit_msg>Better link test<commit_after>'use strict'

const assert = require('chai').assert
const uuid = require('uuid/v4')
const link = require('../../src/utils/link')
const filename = require('../../src/utils/filename')

describe('link()', function() {

	it('should work with an empty data string', function() {

		const html = ''
		const components = []
		const render = () => ''

		const result = link(html, components, render)

		assert.strictEqual(result, html)

	})

	it('should replace names with links', function() {

		const components = [
			{
				// Component with a long path
				id: uuid(),
				src: `${ uuid() }/${ uuid() }/_${ uuid() }.njk`
			},
			{
				// Component with a path
				id: uuid(),
				src: `${ uuid() }/${ uuid() }.njk`
			},
			{
				// Component without a filename only
				id: uuid(),
				src: `${ uuid() }.njk`
			}
		]

		// Component with a name that includes the name of another component
		components.push({
			id: uuid(),
			src: uuid() + components[2].src
		})

		// Unused component
		const untouchedComponent = ({
			id: uuid(),
			src: `${ uuid() }.njk`
		})

		const html = `
			${ components[0].src }
			{% inject "${ components[1].src }" %}
			${ components[2].src }
			${ components[3].src }
			${ untouchedComponent.src }
		`

		// The real renderer gets a safe filename from the link function
		const realRender = (component, filename) => filename

		// The fake renderer needs to escape the filename like the link function does
		const fakeRender = (filename) => [ ...filename ].map((char) => `<span>${ char }</span>`).join('')

		// Removes the filename from a path
		const pathWithoutFilename = (src) => src.replace(filename(src), '')

		const expected = `
			${ pathWithoutFilename(components[0].src) + fakeRender(filename(components[0].src)) }
			{% inject "${ pathWithoutFilename(components[1].src) + fakeRender(filename(components[1].src)) }" %}
			${ fakeRender(filename(components[2].src)) }
			${ fakeRender(filename(components[3].src)) }
			${ untouchedComponent.src }
		`

		const result = link(html, components, realRender)

		assert.strictEqual(result, expected)

	})

})<|endoftext|>