<commit_before>/*
function htmlEncode(value) {
	return value.toString()
		.replace(/&/g,'&').replace(/"/g,'"').replace(/'/g,''')
		.replace(/</g,'<').replace(/>/g,'>')
	; // https://github.com/emn178/js-htmlencode/blob/master/src/htmlencode.js
}
*/

/*
var OptionsSection=function(){
	this.added=[];
};
OptionsSection.prototype.add=function(name,type){
	function getDefaultValue() {
		if (Array.isArray(type)) {
			return
		} else if (type=='bool') {
			return false;
		} else if (type=='color') {
			return {
				r: 1.0,
				g: 1.0,
				b: 1.0,
			};
		}
	}
	this.added.push({
		name: name,
		type: type,
		value: getDefaultValue(),
	});
};

var Options=function(){
	//this.fixed= // TODO stuff like language
	this.code=new OptionsSection();
	this.code.add('clearBackground','bool');
	this.code.add('draw',['triangle','gasket']);
	this.code.add('rotate','bool');
	this.inputs=new OptionsSection(); // TODO recreate based on this.code
	this.inputs.add('fragmentColor','color');
};
*/

function generateCode(options) {
	function indent(level,lines) {
		return lines.map(function(line){
			return Array(level+1).join("	")+line;
		});
	}
	function render() {
		return [].concat(options.clearBackground?[
			"gl.clear(gl.COLOR_BUFFER_BIT);",
		]:[],options.rotate?[
			"gl.uniform1f(rotationAngleLoc,(time-startTime)*360/5000);",
		]:[],[
			"gl.drawArrays(gl.TRIANGLES,0,nVertices);",
		]);
	}
	function colorComponentValue(intName) {
		return options[intName].toFixed(3);
	}
	function colorValue(name) {
		return colorComponentValue(name+'.value.r')+","+
		       colorComponentValue(name+'.value.g')+","+
		       colorComponentValue(name+'.value.b');
	}
	function colorInput(name) {
		return [].concat.apply([],
			['red','green','blue'].map(function(component){
				var c=component.charAt(0);
				var C=c.toUpperCase();
				var intName=name+'.value.'+c;
				var extName='my'+name.charAt(0).toUpperCase()+name.slice(1)+C;
				return [
					"
",
					"	Fragment color: "+component+"",
					"	0% <input id='"+extName+"' type='range' min='0' max='1' step='0.001' value='"+colorComponentValue(intName)+"' /> 100%",
					"
",
				];
			})
		);
	}
	return [].concat([
		"<!DOCTYPE html>",
		"",
		"",
		"<meta charset='utf-8' />",
		"<title>Generated code</title>",
	],options['fragmentColor.input']?[
		"",
	]:[],[
		"",
		"",
		"",
		"",
		"
",
		"	<canvas id='myCanvas' width='512' height='512'></canvas>",
		"
",
	],options['fragmentColor.input']?colorInput('fragmentColor'):[],[
		"",
		"",
		"",
	]).join("\n");
}

function getHtmlDataUri(html) {
	// with base64: https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/btoa
	//return "data:text/html;charset=utf-8;base64,"+window.btoa(unescape(encodeURIComponent(str)));
	// without base64: https://en.wikipedia.org/wiki/Data_URI_scheme
	return 'data:text/html;charset=utf-8,'+encodeURIComponent(html);
}

$(function(){
	$('.webgl-starter').each(function(){
		var container=$(this);
		var options={
			clearBackground: false,
			draw: 'triangle',
			rotate: false,
			// inputs
			'fragmentColor.value.r': 1.0,
			'fragmentColor.value.g': 0.0,
			'fragmentColor.value.b': 0.0,
			'fragmentColor.input': false,
		};
		var code;
		function updateCode() {
			code.text(generateCode(options));
			hljs.highlightBlock(code[0]);
		}
		container.empty().append(
			$("
").append(
				$("").text(" Clear background").prepend( // TODO fix misleading option name - background is clear (transparent) by default
					$("<input type='checkbox'>").change(function(){
						options.clearBackground=$(this).prop('checked');
						updateCode();
					})
				)
			)
		).append(
			$("
").append(
				$("").text("Draw ").append(
					$("<select><option>triangle</option><option>gasket</option></select>").change(function(){
						options.draw=this.value;
						updateCode();
					})
				)
			)
		).append(
			$("
").append(
				$("").text(" Animated rotation").prepend(
					$("<input type='checkbox'>").change(function(){
						options.rotate=$(this).prop('checked');
						updateCode();
					})
				)
			)
		).append(
			$("
").append(
				$("").append("Fragment color: red 0% ").append(
					$("<input type='range' min='0' max='1' step='0.001' value='1'>").change(function(){
						options['fragmentColor.value.r']=parseFloat(this.value);
						updateCode();
					})
				).append(" 100%")
			)
		).append(
			$("
").append(
				$("").append("Fragment color: green 0% ").append(
					$("<input type='range' min='0' max='1' step='0.001' value='0'>").change(function(){
						options['fragmentColor.value.g']=parseFloat(this.value);
						updateCode();
					})
				).append(" 100%")
			)
		).append(
			$("
").append(
				$("").append("Fragment color: blue 0% ").append(
					$("<input type='range' min='0' max='1' step='0.001' value='0'>").change(function(){
						options['fragmentColor.value.b']=parseFloat(this.value);
						updateCode();
					})
				).append(" 100%")
			)
		).append(
			$("
").append(
				$("").text(" Provide fragment color inputs to users").prepend(
					$("<input type='checkbox'>").change(function(){
						options['fragmentColor.input']=$(this).prop('checked');
						updateCode();
					})
				)
			)
		).append(
			$("
").append(code=$("").text(generateCode(options)))
		).append(
			$("
").append(
				$("<button type='button'>Run in new window</button>").click(function(){
					window.open(getHtmlDataUri(code.text()),"generatedCode");
				})
			).append(
				" running in new window doesn't work in Internet Explorer"
			)
		);
		hljs.highlightBlock(code[0]);
	});
});
<commit_msg>user color input works<commit_after>/*
function htmlEncode(value) {
	return value.toString()
		.replace(/&/g,'&').replace(/"/g,'"').replace(/'/g,''')
		.replace(/</g,'<').replace(/>/g,'>')
	; // https://github.com/emn178/js-htmlencode/blob/master/src/htmlencode.js
}
*/

/*
var OptionsSection=function(){
	this.added=[];
};
OptionsSection.prototype.add=function(name,type){
	function getDefaultValue() {
		if (Array.isArray(type)) {
			return
		} else if (type=='bool') {
			return false;
		} else if (type=='color') {
			return {
				r: 1.0,
				g: 1.0,
				b: 1.0,
			};
		}
	}
	this.added.push({
		name: name,
		type: type,
		value: getDefaultValue(),
	});
};

var Options=function(){
	//this.fixed= // TODO stuff like language
	this.code=new OptionsSection();
	this.code.add('clearBackground','bool');
	this.code.add('draw',['triangle','gasket']);
	this.code.add('rotate','bool');
	this.inputs=new OptionsSection(); // TODO recreate based on this.code
	this.inputs.add('fragmentColor','color');
};
*/

function generateCode(options) {
	function indent(level,lines) {
		return lines.map(function(line){
			return Array(level+1).join("	")+line;
		});
	}
	function render() {
		function renderInner() {
			return [].concat(options.clearBackground?[
				"gl.clear(gl.COLOR_BUFFER_BIT);",
			]:[],options.rotate?[
				"gl.uniform1f(rotationAngleLoc,(time-startTime)*360/5000);",
			]:[],[
				"gl.drawArrays(gl.TRIANGLES,0,nVertices);",
			]);
		}
		var lines=[];
		if (options.rotate) {
			lines.push(
				"	var startTime=performance.now();"
			);
		}
		if (options.rotate||options['fragmentColor.input']) {
			lines.push(
				"	function updateCanvas(time) {"
			);
			lines=lines.concat(
				indent(2,renderInner())
			);
			if (options.rotate) {
				lines.push(
					"		requestAnimationFrame(updateCanvas);"
				);
			}
			lines.push(
				"	}"
			);
			if (options.rotate) {
				lines.push(
					"	requestAnimationFrame(updateCanvas);"
				);
			} else {
				lines.push(
					"	updateCanvas();"
				);
			}
		} else {
			lines=lines.concat(
				indent(1,renderInner())
			);
		}
		return lines;
	}
	function colorComponentValue(intName) {
		return options[intName].toFixed(3);
	}
	function colorValue(name) {
		return colorComponentValue(name+'.value.r')+","+
		       colorComponentValue(name+'.value.g')+","+
		       colorComponentValue(name+'.value.b');
	}
	function colorInput(name) {
		return [].concat.apply([],
			['red','green','blue'].map(function(component){
				var c=component.charAt(0);
				var C=c.toUpperCase();
				var intName=name+'.value.'+c;
				var extName='my'+name.charAt(0).toUpperCase()+name.slice(1)+C;
				return [
					"
",
					"	Fragment color: "+component+"",
					"	0% <input id='"+extName+"' type='range' min='0' max='1' step='0.001' value='"+colorComponentValue(intName)+"' /> 100%",
					"
",
				];
			})
		);
	}
	return [].concat([
		"<!DOCTYPE html>",
		"",
		"",
		"<meta charset='utf-8' />",
		"<title>Generated code</title>",
	],options['fragmentColor.input']?[
		"",
	]:[],[
		"",
		"",
		"",
		"",
		"
",
		"	<canvas id='myCanvas' width='512' height='512'></canvas>",
		"
",
	],options['fragmentColor.input']?colorInput('fragmentColor'):[],[
		"",
		"",
		"",
	]).join("\n");
}

function getHtmlDataUri(html) {
	// with base64: https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/btoa
	//return "data:text/html;charset=utf-8;base64,"+window.btoa(unescape(encodeURIComponent(str)));
	// without base64: https://en.wikipedia.org/wiki/Data_URI_scheme
	return 'data:text/html;charset=utf-8,'+encodeURIComponent(html);
}

$(function(){
	$('.webgl-starter').each(function(){
		var container=$(this);
		var options={
			clearBackground: false,
			draw: 'triangle',
			rotate: false,
			// inputs
			'fragmentColor.value.r': 1.0,
			'fragmentColor.value.g': 0.0,
			'fragmentColor.value.b': 0.0,
			'fragmentColor.input': false,
		};
		var code;
		function updateCode() {
			code.text(generateCode(options));
			hljs.highlightBlock(code[0]);
		}
		container.empty().append(
			$("
").append(
				$("").text(" Clear background").prepend( // TODO fix misleading option name - background is clear (transparent) by default
					$("<input type='checkbox'>").change(function(){
						options.clearBackground=$(this).prop('checked');
						updateCode();
					})
				)
			)
		).append(
			$("
").append(
				$("").text("Draw ").append(
					$("<select><option>triangle</option><option>gasket</option></select>").change(function(){
						options.draw=this.value;
						updateCode();
					})
				)
			)
		).append(
			$("
").append(
				$("").text(" Animated rotation").prepend(
					$("<input type='checkbox'>").change(function(){
						options.rotate=$(this).prop('checked');
						updateCode();
					})
				)
			)
		).append(
			$("
").append(
				$("").append("Fragment color: red 0% ").append(
					$("<input type='range' min='0' max='1' step='0.001' value='1'>").change(function(){
						options['fragmentColor.value.r']=parseFloat(this.value);
						updateCode();
					})
				).append(" 100%")
			)
		).append(
			$("
").append(
				$("").append("Fragment color: green 0% ").append(
					$("<input type='range' min='0' max='1' step='0.001' value='0'>").change(function(){
						options['fragmentColor.value.g']=parseFloat(this.value);
						updateCode();
					})
				).append(" 100%")
			)
		).append(
			$("
").append(
				$("").append("Fragment color: blue 0% ").append(
					$("<input type='range' min='0' max='1' step='0.001' value='0'>").change(function(){
						options['fragmentColor.value.b']=parseFloat(this.value);
						updateCode();
					})
				).append(" 100%")
			)
		).append(
			$("
").append(
				$("").text(" Provide fragment color inputs to users").prepend(
					$("<input type='checkbox'>").change(function(){
						options['fragmentColor.input']=$(this).prop('checked');
						updateCode();
					})
				)
			)
		).append(
			$("
").append(code=$("").text(generateCode(options)))
		).append(
			$("
").append(
				$("<button type='button'>Run in new window</button>").click(function(){
					window.open(getHtmlDataUri(code.text()),"generatedCode");
				})
			).append(
				" running in new window doesn't work in Internet Explorer"
			)
		);
		hljs.highlightBlock(code[0]);
	});
});
<|endoftext|>


<commit_before>var Rx = require('rx');
var requestToContext = require('./requestToContext');
var execute = require('./execute');
var FalcorEndpoint = module.exports = {};

FalcorEndpoint.ExpressMiddleware = function(model) {
    return function(req, res, next) {
        var context = requestToContext(req);
        execute(context, function(err, jsong) {
            if (err) {
                res.status(500).send(err);
            } else {
                res.status(200).send(JSON.stringify(jsong));
            }
        });
    };
};

<commit_msg>another bug<commit_after>var Rx = require('rx');
var requestToContext = require('./requestToContext');
var execute = require('./execute');
var FalcorEndpoint = module.exports = {};

FalcorEndpoint.ExpressMiddleware = function(model) {
    var exec = execute(model);
    return function(req, res, next) {
        var context = requestToContext(req);
        exec(context, function(err, jsong) {
            if (err) {
                res.status(500).send(err);
            } else {
                res.status(200).send(JSON.stringify(jsong));
            }
        });
    };
};

<|endoftext|>


<commit_before>/**
 * Install plugin.
 */

function install(Vue) {

    var _ = require('./lib/util')(Vue);

    Vue.url = require('./url')(_);
    Vue.http = require('./http')(_);
    Vue.resource = require('./resource')(_);
    Vue.Promise = require('./promise')(_);

    Object.defineProperties(Vue.prototype, {

        $url: {
            get: function () {
                return _.options(Vue.url, this, this.$options.url);
            }
        },

        $http: {
            get: function () {
                return _.options(Vue.http, this, this.$options.http);
            }
        },

        $resource: {
            get: function () {
                return Vue.resource.bind(this);
            }
        }

    });
}

if (window.Vue) {
    Vue.use(install);
}

module.exports = install;
<commit_msg>add $promise instance method<commit_after>/**
 * Install plugin.
 */

function install(Vue) {

    var _ = require('./lib/util')(Vue);

    Vue.url = require('./url')(_);
    Vue.http = require('./http')(_);
    Vue.resource = require('./resource')(_);
    Vue.Promise = require('./promise')(_);

    Object.defineProperties(Vue.prototype, {

        $url: {
            get: function () {
                return _.options(Vue.url, this, this.$options.url);
            }
        },

        $http: {
            get: function () {
                return _.options(Vue.http, this, this.$options.http);
            }
        },

        $resource: {
            get: function () {
                return Vue.resource.bind(this);
            }
        },

        $promise: {
            get: function () {
                return function (executor) {
                    return new Vue.Promise(executor, this);
                }.bind(this);
            }
        }

    });
}

if (window.Vue) {
    Vue.use(install);
}

module.exports = install;
<|endoftext|>


<commit_before>/**
 * redux-reducers
 * @author Arekkusuva <arekkusuchar@gmail.com>
 * @flow
 */

import { getActionCreatorName } from './helpers';

/**
 * createReducer
 * @description Create reducer, actionTypes and actionCreators.
 * @example
 *  const { actionTypes, actionCreators, reducer } = createReducer(
 *    'user',
 *    { email: '' },
 *    {
 *      'SET_EMAIL': (state, payload) => {
 *         // Your logic here...
 *         return { ...state, email: payload.email }
 *       },
 *       'SAVE': null,
 *       ...etc.
 *    }
 *  )
 * @param storeName - Must begin with a lowercase character.
 * @param initialState {Object}
 * @param configData {Object} - { 'ACTION_TYPE_NAME': Function or null }
 * @returns {{ actionTypes: Object, actionCreators: Object, reducer: Function }}
 */
export const createReducer = (storeName: string, initialState?: Object = {}, configData?: Object = {}) => {
  const actionTypes: Object = {};
  const actionCreator = (actionTypeName, payload) => ({ type: actionTypeName, payload });
  const setterActionName: string = `set${storeName.charAt(0).toUpperCase()}${storeName.slice(1)}`;
  const setterActionCreatorName = `${storeName}/${setterActionName}`;
  const actionCreators: Object = {
    [setterActionName]: payload => actionCreator(setterActionCreatorName, payload),
  };
  const tmpActionTypesHandlers: Object = {};

  Object.keys(configData).forEach((actionType) => {
    const actionCreatorName: string = getActionCreatorName(actionType);
    if (setterActionName !== actionCreatorName) {
      const actionTypeName = `${storeName}/${actionCreatorName}`;
      if (typeof configData[actionType] === 'function') {
        tmpActionTypesHandlers[actionTypeName] = configData[actionType];
      }
      actionTypes[actionType] = actionTypeName;
      actionCreators[actionCreatorName] =
        payload => actionCreator(actionTypeName, payload);
    }
  });
  const reducer: Function = (state?: Object = initialState, action: Object) => {
    const tmpActionTypeHandler = tmpActionTypesHandlers[action.type];
    if (typeof tmpActionTypeHandler === 'function') {
      return () => tmpActionTypeHandler(state, action.payload);
    }
    if (action.type === setterActionCreatorName) {
      return {
        ...state,
        ...action.payload,
      };
    }
    return state;
  };

  return {
    actionTypes,
    actionCreators,
    reducer,
  };
};
<commit_msg>Add mixReducers<commit_after>/**
 * redux-reducers
 * @author Arekkusuva <arekkusuchar@gmail.com>
 * @flow
 */

import { getActionCreatorName } from './helpers';

/**
 * createReducer
 * @description Create reducer, actionTypes and actionCreators.
 * @example
 *  export default createReducer(
 *    'user',
 *    { email: '' },
 *    {
 *      'SET_EMAIL': (state, payload) => {
 *         // Your logic here...
 *         return { ...state, email: payload.email }
 *       },
 *       'SAVE': null,
 *       ...etc.
 *    }
 *  );
 * @param reducerName - Must begin with a lowercase character.
 * @param initialState {Object}
 * @param configData {Object} - { 'ACTION_TYPE_NAME': Function or null }
 * @returns {{ actionTypes: Object, actionCreators: Object, reducer: Function }}
 */
export const createReducer = (reducerName: string, initialState?: Object = {}, configData?: Object = {}) => {
  const actionTypes: Object = {};
  const actionCreator = (actionTypeName, payload) => ({ type: actionTypeName, payload });
  const setterActionName: string = `set${reducerName.charAt(0).toUpperCase()}${reducerName.slice(1)}`;
  const setterActionCreatorName = `${reducerName}/${setterActionName}`;
  const actionCreators: Object = {
    [setterActionName]: payload => actionCreator(setterActionCreatorName, payload),
  };
  const tmpActionTypesHandlers: Object = {};

  Object.keys(configData).forEach((actionType) => {
    const actionCreatorName: string = getActionCreatorName(actionType);
    if (setterActionName !== actionCreatorName) {
      const actionTypeName = `${reducerName}/${actionCreatorName}`;
      if (typeof configData[actionType] === 'function') {
        tmpActionTypesHandlers[actionTypeName] = configData[actionType];
      }
      actionTypes[actionType] = actionTypeName;
      actionCreators[actionCreatorName] =
        payload => actionCreator(actionTypeName, payload);
    }
  });
  const reducer: Function = (state?: Object = initialState, action: Object) => {
    const tmpActionTypeHandler = tmpActionTypesHandlers[action.type];
    if (typeof tmpActionTypeHandler === 'function') {
      return () => tmpActionTypeHandler(state, action.payload);
    }
    if (action.type === setterActionCreatorName) {
      return {
        ...state,
        ...action.payload,
      };
    }
    return state;
  };

  return {
    reducerName,
    actionTypes,
    actionCreators,
    reducer,
  };
};

/**
 * mixReducers
 * @description Combine redux usual reducers and reducers created by this library.
 * @param combiner {Function}
 * @param mixedReducers {Array}
 * @returns {*}
 */
export const mixReducers = (combiner: Function, mixedReducers: ?Array<Object>) => {
  const reducers: Object = {};
  mixedReducers.forEach((item) => {
    if (typeof item === 'function') reducers[item.name] = item;
    else if (item.reducer) reducers[item.reducerName] = item.reducer;
  });
  return combiner(reducers);
};
<|endoftext|>


<commit_before>'use strict';

var polyfills = require('famous-polyfills');
var rAF = polyfills.requestAnimationFrame;

var _now;
if (typeof performance !== 'undefined') {
    _now = function() {
        return performance.now();
    };
}
else {
    _now = Date.now;
}

if (typeof document !== 'undefined') {
    var VENDOR_HIDDEN, VENDOR_VISIBILITY_CHANGE;

    if (typeof document.hidden !== 'undefined') { // Opera 12.10 and Firefox 18 and later support
        VENDOR_HIDDEN = 'hidden';
        VENDOR_VISIBILITY_CHANGE = 'visibilitychange';
    }
    else if (typeof document.mozHidden !== 'undefined') {
        VENDOR_HIDDEN = 'mozHidden';
        VENDOR_VISIBILITY_CHANGE = 'mozvisibilitychange';
    }
    else if (typeof document.msHidden !== 'undefined') {
        VENDOR_HIDDEN = 'msHidden';
        VENDOR_VISIBILITY_CHANGE = 'msvisibilitychange';
    }
    else if (typeof document.webkitHidden !== 'undefined') {
        VENDOR_HIDDEN = 'webkitHidden';
        VENDOR_VISIBILITY_CHANGE = 'webkitvisibilitychange';
    }
}

function Engine() {
    this._updates = [];
    var _this = this;
    this.looper = function(time) {
        _this.loop(time);
    };
    this._looper = this.loop.bind(this);
    this._stoppedAt = _now();
    this._sleep = 0;
    this._startOnVisibilityChange = true;
    this.start();

    if (typeof document !== 'undefined') {
        var _this = this;
        document.addEventListener(VENDOR_VISIBILITY_CHANGE, function() {
            if (document[VENDOR_HIDDEN]) {
                var startOnVisibilityChange = _this._startOnVisibilityChange;
                _this.stop();
                _this._startOnVisibilityChange = startOnVisibilityChange;
            }
            else {
                if (_this._startOnVisibilityChange) {
                    rAF(function() {
                        _this.start();
                    });
                }
            }
        });
    }
}

Engine.prototype.start = function start() {
    this._startOnVisibilityChange = true;
    this._running = true;
    this._sleep += _now() - this._stoppedAt;
    rAF(this._looper);
    return this;
};

Engine.prototype.stop = function stop() {
    this._startOnVisibilityChange = false;
    this._running = false;
    this._stoppedAt = _now();
    return this;
};

Engine.prototype.isRunning = function isRunning() {
    return this._running;
};

Engine.prototype.step = function step (time) {
    for (var i = 0, len = this._updates.length ; i < len ; i++) {
        this._updates[i].update(time);
    }
    return this;
};

Engine.prototype.loop = function loop(time) {
    this.step(time - this._sleep);
    if (this._running) {
        rAF(this._looper);
    }
    return this;
};

Engine.prototype.update = function update(item) {
    if (this._updates.indexOf(item) === -1) this._updates.push(item);
    return this;
};

Engine.prototype.noLongerUpdate = function noLongerUpdate(item) {
    var index = this._updates.indexOf(item);
    if (index > -1) {
        this._updates.splice(index, 1);
    }
    return this;
};

module.exports = Engine;
<commit_msg>fix: fix rAF bugs<commit_after>'use strict';

var polyfills = require('famous-polyfills');
var rAF = polyfills.requestAnimationFrame;

var _now;
if (typeof performance !== 'undefined') {
    _now = function() {
        return performance.now();
    };
}
else {
    _now = Date.now;
}

if (typeof document !== 'undefined') {
    var VENDOR_HIDDEN, VENDOR_VISIBILITY_CHANGE;

    if (typeof document.hidden !== 'undefined') { // Opera 12.10 and Firefox 18 and later support
        VENDOR_HIDDEN = 'hidden';
        VENDOR_VISIBILITY_CHANGE = 'visibilitychange';
    }
    else if (typeof document.mozHidden !== 'undefined') {
        VENDOR_HIDDEN = 'mozHidden';
        VENDOR_VISIBILITY_CHANGE = 'mozvisibilitychange';
    }
    else if (typeof document.msHidden !== 'undefined') {
        VENDOR_HIDDEN = 'msHidden';
        VENDOR_VISIBILITY_CHANGE = 'msvisibilitychange';
    }
    else if (typeof document.webkitHidden !== 'undefined') {
        VENDOR_HIDDEN = 'webkitHidden';
        VENDOR_VISIBILITY_CHANGE = 'webkitvisibilitychange';
    }
}

function Engine() {
    this._updates = [];
    var _this = this;
    this.looper = function(time) {
        _this.loop(time);
    };
    this._stoppedAt = _now();
    this._sleep = 0;
    this._startOnVisibilityChange = true;
    this.start();
    rAF(this.looper);

    if (typeof document !== 'undefined') {
        var _this = this;
        document.addEventListener(VENDOR_VISIBILITY_CHANGE, function() {
            if (document[VENDOR_HIDDEN]) {
                var startOnVisibilityChange = _this._startOnVisibilityChange;
                _this.stop();
                _this._startOnVisibilityChange = startOnVisibilityChange;
            }
            else {
                if (_this._startOnVisibilityChange) {
                    _this.start();
                }
            }
        });
    }
}

Engine.prototype.start = function start() {
    this._startOnVisibilityChange = true;
    this._running = true;
    this._sleep += _now() - this._stoppedAt;
    return this;
};

Engine.prototype.stop = function stop() {
    this._startOnVisibilityChange = false;
    this._running = false;
    this._stoppedAt = _now();
    return this;
};

Engine.prototype.isRunning = function isRunning() {
    return this._running;
};

Engine.prototype.step = function step (time) {
    for (var i = 0, len = this._updates.length ; i < len ; i++) {
        this._updates[i].update(time);
    }
    return this;
};

Engine.prototype.loop = function loop(time) {
    this.step(time - this._sleep);
    if (this._running) {
        rAF(this.looper);
    }
    return this;
};

Engine.prototype.update = function update(item) {
    if (this._updates.indexOf(item) === -1) this._updates.push(item);
    return this;
};

Engine.prototype.noLongerUpdate = function noLongerUpdate(item) {
    var index = this._updates.indexOf(item);
    if (index > -1) {
        this._updates.splice(index, 1);
    }
    return this;
};

module.exports = Engine;
<|endoftext|>


<commit_before>// var allBrews = require('../views/allBrews.hbs');
var brewProfile = require('../views/brewProfile.hbs');
var userHome = require('../views/userHome.hbs');
var brewOptions = require('../views/brewOptions.hbs');
var request = require('superagent');
var handlebars = require('handlebars');
var $ = require('jquery')

$(document).ready(function(){
  $('#showBtn').click(function(){
  showAllBeers()
})
})

function showAllBeers() {
  request.get('/allBrews')
  .end(function(err,res){
    // console.log('this is res',res)
    var list = allBrews({data:res.body})
    document.body.innerHTML = list

     $('.viewBtn').click(function(e){
       e.preventDefault()
       var id = e.target.id
       getAndShowProfile(id)
    })
  })
}

function getAndShowProfile(id) {
   request.get('/brews/'+id)
   .end(function(err,res){
   var htmlFromTemplate = brewProfile(res.body)
   document.body.innerHTML = htmlFromTemplate
   $('#backBtn').click(function(){
   showAllBeers()
     })
   })
 }
<commit_msg>uncomment index.js<commit_after>var userHome = require('../views/userHome.hbs');
var allBrews = require('../views/allBrews.hbs');
var brewProfile = require('../views/brewProfile.hbs');
var brewOptions = require('../views/brewOptions.hbs');
var request = require('superagent');
var handlebars = require('handlebars');
var $ = require('jquery')

$(document).ready(function(){
  $('#showBtn').click(function(){
  showAllBeers()
})
})

function showAllBeers() {
  request.get('/allBrews')
  .end(function(err,res){
    // console.log('this is res',res)
    var list = allBrews({data:res.body})
    document.body.innerHTML = list

     $('.viewBtn').click(function(e){
       e.preventDefault()
       var id = e.target.id
       getAndShowProfile(id)
    })
  })
}

function getAndShowProfile(id) {
   request.get('/brews/'+id)
   .end(function(err,res){
   var htmlFromTemplate = brewProfile(res.body)
   document.body.innerHTML = htmlFromTemplate
   $('#backBtn').click(function(){
   showAllBeers()
     })
   })
 }
<|endoftext|>


<commit_before>/*jslint node : true, nomen: true, plusplus: true, vars: true*/
"use strict";

var log4js = require('log4js');
var reqLogger = require('./request-logger');

module.exports = function (options, imports, register) {
    var hub = imports.hub;

    if (options.config) {
        log4js.configure(options.config);
    }

    log4js.requetLogger = reqLogger(options.request || {}, log4js);

    var logger = log4js.getLogger('app');

    hub.on('log.error', logger.error.bind(logger));
    hub.on('log.info', logger.info.bind(logger));

    register(null, {log: log4js});
};

module.exports.provides = ['log'];
module.exports.consumes = ['hub'];
<commit_msg>fix ugly typo<commit_after>/*jslint node : true, nomen: true, plusplus: true, vars: true*/
"use strict";

var log4js = require('log4js');
var reqLogger = require('./request-logger');

module.exports = function (options, imports, register) {
    var hub = imports.hub;

    if (options.config) {
        log4js.configure(options.config);
    }

    log4js.requestLogger = reqLogger(options.request || {}, log4js);

    var logger = log4js.getLogger('app');

    hub.on('log.error', logger.error.bind(logger));
    hub.on('log.info', logger.info.bind(logger));

    register(null, {log: log4js});
};

module.exports.provides = ['log'];
module.exports.consumes = ['hub'];
<|endoftext|>


<commit_before>'use strict';

require('angular')
  .module('animate-change', [])
  .directive('animateChange', require('./directive'));

module.exports = 'animate-change';
<commit_msg>simplify module<commit_after>'use strict';

module.exports = require('angular')
  .module('animate-change', [])
  .directive('animateChange', require('./directive'))
  .name;
<|endoftext|>


<commit_before>import React from 'react';
import ReactDOM from 'react-dom';
import Homepage from './components/Homepage';
import Docs from './containers/Docs';
import { Router, Route, browserHistory, applyRouterMiddleware } from 'react-router';
import { useScroll } from 'react-router-scroll';
import 'bootstrap/dist/css/bootstrap.css';
import './index.css';
import './lib/autolinker';

ReactDOM.render(
  (
    <Router
      history={browserHistory}
      render={applyRouterMiddleware(useScroll())}
    >
      <Route path="/" component={Homepage} />
      <Route path="/docs(/:sectionId/(:itemId))" component={Docs} />

    </Router>
  ),
  document.getElementById('root')
);
<commit_msg>Remove autoscroll to see it works on Google.<commit_after>import React from 'react';
import ReactDOM from 'react-dom';
import Homepage from './components/Homepage';
import Docs from './containers/Docs';
import { Router, Route, browserHistory, applyRouterMiddleware } from 'react-router';
import { useScroll } from 'react-router-scroll';
import 'bootstrap/dist/css/bootstrap.css';
import './index.css';
import './lib/autolinker';

ReactDOM.render(
  (
    <Router
      history={browserHistory}
    >
      <Route path="/" component={Homepage} />
      <Route path="/docs(/:sectionId/(:itemId))" component={Docs} />

    </Router>
  ),
  document.getElementById('root')
);
<|endoftext|>


<commit_before>#! /usr/local/bin/node
// @flow
import program from "commander";
import prettier from "prettier";
import yaml from "js-yaml";
import fs from "fs";
import path from "path";

// Swagger data types are base on types supported by the JSON-Scheme Draft4.
const typeMapping = {
  array: "Array<*>",
  boolean: "boolean",
  integer: "number",
  number: "number",
  null: "null",
  object: "Object",
  string: "string"
};

export class FlowTypeGenerator {
  result: string;
  +withExport: boolean;
  +swagger: Object;

  constructor(swagger: Object, withExport: boolean = true) {
    if (!swagger) {
      throw new Error("Can't create FlowTypeGenerator");
    }
    this.result = "// @flow \n";
    (this: any).withExport = withExport;
    (this: any).swagger = swagger;
  }

  static isPrimitiveType(type: string) {
    return ["integer", "number", "string", "boolean"].indexOf(type) !== -1;
  }

  static definitionType(ref: string) {
    const re = /#\/definitions\/(.*)/;
    const found = ref.match(re);
    return found ? found[1] : "";
  }

  static hasNext(key: string, definitions: Object) {
    const keys = Object.keys(definitions);
    return keys.findIndex(v => v === key) < keys.length - 1;
  }

  definitions(): string {
    const { definitions } = this.swagger;
    Object.keys(definitions).forEach((k) => {
      const headLine = this.withExport ? `export type ${k} = ` : `type ${k} = `;
      this.appendResult(headLine);
      this.determineTypes(k, definitions, true);
      this.appendResult("\n");
    });
    return this.result;
  }

  appendResult(text: string) {
    this.result += text;
  }

  determineTypes(key: string, properties: Object, isPrimary: boolean = false) {
    const property = properties[key];
    if ("$ref" in property) {
      this.appendResult(
        `${key}: ${FlowTypeGenerator.definitionType(property.$ref)}`
      );
      if (FlowTypeGenerator.hasNext(key, properties)) {
        this.appendResult(",");
      }
    }

    if (FlowTypeGenerator.isPrimitiveType(property.type)) {
      this.appendResult(`${key}: ${typeMapping[property.type]}`);
      if (FlowTypeGenerator.hasNext(key, properties)) {
        this.appendResult(",");
      }
    }

    if (property.type === "object") {
      if ("properties" in property) {
        if (!isPrimary) {
          this.appendResult(`${key}: `);
        }
        this.appendResult("{");
        Object.keys(property.properties).forEach((k) => {
          this.determineTypes(k, property.properties);
        });
        this.appendResult("}");
        if (FlowTypeGenerator.hasNext(key, properties) && !isPrimary) {
          this.appendResult(",");
        }
      } else if (isPrimary) {
        this.appendResult(`${typeMapping[property.type]}`);
      } else {
        this.appendResult(`${key}: ${typeMapping[property.type]}`);
        if (FlowTypeGenerator.hasNext(key, properties)) {
          this.appendResult(",");
        }
      }
    }

    if (property.type === "array") {
      const type: * = "$ref" in property.items
        ? FlowTypeGenerator.definitionType(property.items.$ref)
        : property.items.type;
      const typeString = `Array<${type}>`;
      this.appendResult(`${key}: ${typeString}`);
      if (FlowTypeGenerator.hasNext(key, properties)) {
        this.appendResult(",");
      }
    }
  }
}

export const generator = (file: string) => {
  const doc: Object = path.extname(file) === ".yaml"
    ? yaml.safeLoad(fs.readFileSync(file, "utf8"))
    : JSON.parse(fs.readFileSync(file, "utf8"));
  const g = new FlowTypeGenerator(doc);
  const options = {};
  return prettier.format(g.definitions(), options);
};

export const writeToFile = (dist: string = "./flowtype.js", result: string) => {
  fs.writeFile(dist, result, (err) => {
    if (err) {
      throw err;
    }
  });
};

export const distFile = (p: Object) => p.distination || "./flowtype.js";

program
  .arguments("<file>")
  .option("-d --distination <distination>", "Distination path")
  .action((file) => {
    try {
      const result = generator(file);
      const dist = distFile(program);
      writeToFile(dist, result);
      console.log(`Generated flow types to ${dist}`);
    } catch (e) {
      console.log(e);
    }
  })
  .parse(process.argv);
<commit_msg>Fix node path #1<commit_after>#! /usr/bin/env node
// @flow
import program from "commander";
import prettier from "prettier";
import yaml from "js-yaml";
import fs from "fs";
import path from "path";

// Swagger data types are base on types supported by the JSON-Scheme Draft4.
const typeMapping = {
  array: "Array<*>",
  boolean: "boolean",
  integer: "number",
  number: "number",
  null: "null",
  object: "Object",
  string: "string"
};

export class FlowTypeGenerator {
  result: string;
  +withExport: boolean;
  +swagger: Object;

  constructor(swagger: Object, withExport: boolean = true) {
    if (!swagger) {
      throw new Error("Can't create FlowTypeGenerator");
    }
    this.result = "// @flow \n";
    (this: any).withExport = withExport;
    (this: any).swagger = swagger;
  }

  static isPrimitiveType(type: string) {
    return ["integer", "number", "string", "boolean"].indexOf(type) !== -1;
  }

  static definitionType(ref: string) {
    const re = /#\/definitions\/(.*)/;
    const found = ref.match(re);
    return found ? found[1] : "";
  }

  static hasNext(key: string, definitions: Object) {
    const keys = Object.keys(definitions);
    return keys.findIndex(v => v === key) < keys.length - 1;
  }

  definitions(): string {
    const { definitions } = this.swagger;
    Object.keys(definitions).forEach(k => {
      const headLine = this.withExport ? `export type ${k} = ` : `type ${k} = `;
      this.appendResult(headLine);
      this.determineTypes(k, definitions, true);
      this.appendResult("\n");
    });
    return this.result;
  }

  appendResult(text: string) {
    this.result += text;
  }

  determineTypes(key: string, properties: Object, isPrimary: boolean = false) {
    const property = properties[key];
    if ("$ref" in property) {
      this.appendResult(
        `${key}: ${FlowTypeGenerator.definitionType(property.$ref)}`
      );
      if (FlowTypeGenerator.hasNext(key, properties)) {
        this.appendResult(",");
      }
    }

    if (FlowTypeGenerator.isPrimitiveType(property.type)) {
      this.appendResult(`${key}: ${typeMapping[property.type]}`);
      if (FlowTypeGenerator.hasNext(key, properties)) {
        this.appendResult(",");
      }
    }

    if (property.type === "object") {
      if ("properties" in property) {
        if (!isPrimary) {
          this.appendResult(`${key}: `);
        }
        this.appendResult("{");
        Object.keys(property.properties).forEach(k => {
          this.determineTypes(k, property.properties);
        });
        this.appendResult("}");
        if (FlowTypeGenerator.hasNext(key, properties) && !isPrimary) {
          this.appendResult(",");
        }
      } else if (isPrimary) {
        this.appendResult(`${typeMapping[property.type]}`);
      } else {
        this.appendResult(`${key}: ${typeMapping[property.type]}`);
        if (FlowTypeGenerator.hasNext(key, properties)) {
          this.appendResult(",");
        }
      }
    }

    if (property.type === "array") {
      const type: * = "$ref" in property.items
        ? FlowTypeGenerator.definitionType(property.items.$ref)
        : property.items.type;
      const typeString = `Array<${type}>`;
      this.appendResult(`${key}: ${typeString}`);
      if (FlowTypeGenerator.hasNext(key, properties)) {
        this.appendResult(",");
      }
    }
  }
}

export const generator = (file: string) => {
  const doc: Object = path.extname(file) === ".yaml"
    ? yaml.safeLoad(fs.readFileSync(file, "utf8"))
    : JSON.parse(fs.readFileSync(file, "utf8"));
  const g = new FlowTypeGenerator(doc);
  const options = {};
  return prettier.format(g.definitions(), options);
};

export const writeToFile = (dist: string = "./flowtype.js", result: string) => {
  fs.writeFile(dist, result, err => {
    if (err) {
      throw err;
    }
  });
};

export const distFile = (p: Object) => p.distination || "./flowtype.js";

program
  .arguments("<file>")
  .option("-d --distination <distination>", "Distination path")
  .action(file => {
    try {
      const result = generator(file);
      const dist = distFile(program);
      writeToFile(dist, result);
      console.log(`Generated flow types to ${dist}`);
    } catch (e) {
      console.log(e);
    }
  })
  .parse(process.argv);
<|endoftext|>


<commit_before>import React from 'react';
import ReactDOM from 'react-dom';
import isFunction from 'lodash/isFunction';
import merge from 'lodash/merge';
import filter from 'lodash/filter';
import keys from 'lodash/keys';

import computePosition from './computePosition';
import computeDeltas from './computeDeltas';

const T = React.PropTypes;

const POSITION_KEYS = ['left', 'top', 'bottom', 'right', 'translateX', 'translateY'];

class Touchable extends React.Component {
  static propTypes = {
    children: T.oneOfType([T.func, T.element]).isRequired,
    style: T.objectOf(T.oneOfType([T.number, T.object])).isRequired,
    onTouchStart: T.func,
    onTouchEnd: T.func,
    onTouchMove: T.func,
    onSwipe: T.func,
    onHold: T.func,
  };

  state = {
    component: {
      initial: computePosition(this.props.style, { dx: 0, dy: 0 }),
      current: computePosition(this.props.style, { dx: 0, dy: 0 }),
    },
    touch: {
      initial: null,
      current: null,
    }
  };

  onTouchStart(e) {
    // TODO: touches, targetTouches, or changedTouches
    const { clientX: x, clientY: y } = e.nativeEvent.touches[0];
    this.setState({
      touch: {initial: { x, y }, current: { x, y }}
    });

    this._callPropsHandler('onTouchStart', e);
  }

  onTouchMove(e) {
    const { clientX: x, clientY: y } = e.nativeEvent.touches[0];

    const deltas = computeDeltas(this.state.touch.current, { x, y });
    const positionStyle = computePosition(this.state.component.current, deltas);

    this.setState({
      touch: {current: { x, y }},
      component: {current: positionStyle},
    });

    this._callPropsHandler('onTouchMove', e);
  }

  onTouchEnd(e) {
    this._callPropsHandler('onTouchEnd', e);
  }

  _callPropsHandler(name, e) {
    // handle user's touch handling
    this.props[name] && this.props[name](e);
  }

  render() {
    const { children } = this.props;
    const { component: position } = this.state;

    const renderedChildren = isFunction(children) ? children(position.current) : children;
    return React.cloneElement(React.Children.only(renderedChildren), {
      onTouchStart: e => this.onTouchStart(e),
      onTouchMove: e => this.onTouchMove(e),
      onTouchEnd: e => this.onTouchEnd(e),
    });
  }
}

export default Touchable;
<commit_msg>remove this unused line<commit_after>import React from 'react';
import ReactDOM from 'react-dom';
import isFunction from 'lodash/isFunction';
import merge from 'lodash/merge';
import filter from 'lodash/filter';
import keys from 'lodash/keys';

import computePosition from './computePosition';
import computeDeltas from './computeDeltas';

const T = React.PropTypes;

class Touchable extends React.Component {
  static propTypes = {
    children: T.oneOfType([T.func, T.element]).isRequired,
    style: T.objectOf(T.oneOfType([T.number, T.object])).isRequired,
    onTouchStart: T.func,
    onTouchEnd: T.func,
    onTouchMove: T.func,
    onSwipe: T.func,
    onHold: T.func,
  };

  state = {
    component: {
      initial: computePosition(this.props.style, { dx: 0, dy: 0 }),
      current: computePosition(this.props.style, { dx: 0, dy: 0 }),
    },
    touch: {
      initial: null,
      current: null,
    }
  };

  onTouchStart(e) {
    // TODO: touches, targetTouches, or changedTouches
    const { clientX: x, clientY: y } = e.nativeEvent.touches[0];
    this.setState({
      touch: {initial: { x, y }, current: { x, y }}
    });

    this._callPropsHandler('onTouchStart', e);
  }

  onTouchMove(e) {
    const { clientX: x, clientY: y } = e.nativeEvent.touches[0];

    const deltas = computeDeltas(this.state.touch.current, { x, y });
    const positionStyle = computePosition(this.state.component.current, deltas);

    this.setState({
      touch: {current: { x, y }},
      component: {current: positionStyle},
    });

    this._callPropsHandler('onTouchMove', e);
  }

  onTouchEnd(e) {
    this._callPropsHandler('onTouchEnd', e);
  }

  _callPropsHandler(name, e) {
    // handle user's touch handling
    this.props[name] && this.props[name](e);
  }

  render() {
    const { children } = this.props;
    const { component: position } = this.state;

    const renderedChildren = isFunction(children) ? children(position.current) : children;
    return React.cloneElement(React.Children.only(renderedChildren), {
      onTouchStart: e => this.onTouchStart(e),
      onTouchMove: e => this.onTouchMove(e),
      onTouchEnd: e => this.onTouchEnd(e),
    });
  }
}

export default Touchable;
<|endoftext|>


<commit_before>import _          from 'lodash';
import {readFileSync} from 'fs';
import {resolve}  from 'path';
import isThere    from 'is-there';
import json5      from 'json5';
import sass       from 'node-sass';

export default function(url, prev) {
  if (!/\.json5?$/.test(url)) {
    return sass.NULL;
  }

  let includePaths = this.options.includePaths ? this.options.includePaths.split(':') : [];
  let paths = []
    .concat(prev.slice(0, prev.lastIndexOf('/')))
    .concat(includePaths);

  let files = paths
    .map(path => resolve(path, url))
    .filter(isThere);

  if (files.length === 0) {
    return new Error(`Unable to find "${url}" from the following path(s): ${paths.join(', ')}. Check includePaths.`);
  }

  return {
    contents: json5.parse(readFileSync(files[0]))
  };
}

function parseJSON(json) {
  return Object.keys(json)
    .map(key => `$${key}: ${parseValue(json[key])};`)
    .join('\n');
}

function parseValue(value) {
  if (_.isArray(value)) {
    return parseList(value);
  } else if (_.isPlainObject(value)) {
    return parseMap(value);
  } else {
    return value;
  }
}

function parseList(list) {
  return `(${list
    .map(value => parseValue(value))
    .join(',')})`;
}

function parseMap(map) {
  return `(${Object.keys(map)
    .map(key => `${key}: ${parseValue(map[key])}`)
    .join(',')})`;
}
<commit_msg>Fixed the last change<commit_after>import _          from 'lodash';
import {readFileSync} from 'fs';
import {resolve}  from 'path';
import isThere    from 'is-there';
import json5      from 'json5';
import sass       from 'node-sass';

export default function(url, prev) {
  if (!/\.json5?$/.test(url)) {
    return sass.NULL;
  }

  let includePaths = this.options.includePaths ? this.options.includePaths.split(':') : [];
  let paths = []
    .concat(prev.slice(0, prev.lastIndexOf('/')))
    .concat(includePaths);

  let files = paths
    .map(path => resolve(path, url))
    .filter(isThere);

  if (files.length === 0) {
    return new Error(`Unable to find "${url}" from the following path(s): ${paths.join(', ')}. Check includePaths.`);
  }

  return {
    contents: parseJSON(json5.parse(readFileSync(files[0])))
  };
}

function parseJSON(json) {
  return Object.keys(json)
    .map(key => `$${key}: ${parseValue(json[key])};`)
    .join('\n');
}

function parseValue(value) {
  if (_.isArray(value)) {
    return parseList(value);
  } else if (_.isPlainObject(value)) {
    return parseMap(value);
  } else {
    return value;
  }
}

function parseList(list) {
  return `(${list
    .map(value => parseValue(value))
    .join(',')})`;
}

function parseMap(map) {
  return `(${Object.keys(map)
    .map(key => `${key}: ${parseValue(map[key])}`)
    .join(',')})`;
}
<|endoftext|>


<commit_before>//Requirements
import Discord from 'discord.js';
import config from './config.json';
import {getMenu, SetCWeekMenuURL} from './Functions.js';
import {returnThisDay, saveMessage} from './Utility.js';
import responses from './responses.json';
import schedule from 'node-schedule';

// Needed for async to work
require("babel-core/register");
require("babel-polyfill");

const bot = new Discord.Client();

bot.login(config.token)
.catch((e) => {
	console.log(e);
})

//Informs successful login to the console
bot.on('ready', () => {
	console.log('Connected');
	console.log("Bot has started. Logged in as " + bot.user.username + ". Connected to " + bot.guilds.size + " servers");
	bot.user.setGame(config.currentGame);
});

//Schedules, updates every day at 7:00AM. Fetches JSON file from Arkea website and extracts the information. Prints corresponding information for each day.
let j = schedule.scheduleJob('0 7 * * *', () => {
	// Empty config.json to gitignore plsss
 	let channel = bot.guilds.get(config.guildID).channels.get(config.menuChannelID);
	let result = SetCWeekMenuURL("79be4e48-b6ad-e711-a207-005056820ad4");
	let day = returnThisDay();
	getMenu(result, day, channel)
});

bot.on('message', (message) => {
	let content = message.content.toLowerCase();
	if (content.substring(0, 1) == config.prefix) {
		let args = content.substring(1).split(' ');
		let cmd = args[0];
		//List of awailable commands
		switch(cmd) {
			//Random command, mainly for test purposes
			case 'test':
				message.channel.sendMessage("Hello!");
				break;

			//WIP under this line
			//-------------------------------------------
			case 'help':
				message.channel.sendMessage("Commands:");
				break;
		}
	}
});

//To "star" message when star reaction is added
bot.on('messageReactionAdd', (reaction, user) => {
	if (reaction.emoji == "⭐" && reaction.message.guild)
		saveMessage(user, reaction)
});
<commit_msg>Fixed stuff to work with async<commit_after>//Requirements
import Discord from 'discord.js';
import config from './config.json';
import {getMenu, SetCWeekMenuURL} from './Functions.js';
import {returnThisDay, ConvertToISO, saveMessage} from './Utility.js';
import responses from './responses.json';
import schedule from 'node-schedule';

// Needed for async to work
require("babel-core/register");
require("babel-polyfill");

const bot = new Discord.Client();

bot.login(config.token)
.catch((e) => {
	console.log(e);
})

//Informs successful login to the console
bot.on('ready', () => {
	console.log('Connected');
	console.log("Bot has started. Logged in as " + bot.user.username + ". Connected to " + bot.guilds.size + " servers");
	bot.user.setGame(config.currentGame);
});

//Schedules, updates every day at 7:00AM. Fetches JSON file from Arkea website and extracts the information. Prints corresponding information for each day.
let j = schedule.scheduleJob('0 7 * * *', async () => {
	// Empty config.json to gitignore plsss
 	let channel = bot.guilds.get(config.guildID).channels.get(config.menuChannelID);
	let result = await SetCWeekMenuURL(config.restaurantID);
	let day = returnThisDay();
	getMenu(result, day, channel);
});

bot.on('message', async (message) => {
	let content = message.content.toLowerCase();
	if (content.substring(0, 1) == config.prefix) {
		let args = content.substring(1).split(' ');
		let cmd = args[0];

		//List of awailable commands
		switch(cmd) {
			//Random command, mainly for test purposes
			case 'test':
				message.channel.send("Hello!");
				break;

			//WIP
			case 'help':
				message.channel.send("Commands:");
				//message.channel.send(message.channel);
				break;

			//WIP
			case 'menu':
				let day = ConvertToISO(args[1]);
				let result = await SetCWeekMenuURL(config.restaurantID, day);
				await getMenu(result, day, message.channel);
				break;
		}
	}
});

//To "star" message when star reaction is added
bot.on('messageReactionAdd', (reaction, user) => {
	if (reaction.emoji == "⭐" && reaction.message.guild)
		saveMessage(user, reaction)
});
<|endoftext|>


<commit_before>import {DOM, FEATURE} from 'aurelia-pal';

let hasSetImmediate = typeof setImmediate === 'function';
const stackSeparator = '\nEnqueued in TaskQueue by:\n';
const microStackSeparator = '\nEnqueued in MicroTaskQueue by:\n';

function makeRequestFlushFromMutationObserver(flush) {
  let toggle = 1;
  let observer = DOM.createMutationObserver(flush);
  let node = DOM.createTextNode('');
  observer.observe(node, {characterData: true});
  return function requestFlush() {
    toggle = -toggle;
    node.data = toggle;
  };
}

function makeRequestFlushFromTimer(flush) {
  return function requestFlush() {
    // We dispatch a timeout with a specified delay of 0 for engines that
    // can reliably accommodate that request. This will usually be snapped
    // to a 4 milisecond delay, but once we're flushing, there's no delay
    // between events.
    let timeoutHandle = setTimeout(handleFlushTimer, 0);
    // However, since this timer gets frequently dropped in Firefox
    // workers, we enlist an interval handle that will try to fire
    // an event 20 times per second until it succeeds.
    let intervalHandle = setInterval(handleFlushTimer, 50);
    function handleFlushTimer() {
      // Whichever timer succeeds will cancel both timers and request the
      // flush.
      clearTimeout(timeoutHandle);
      clearInterval(intervalHandle);
      flush();
    }
  };
}

function onError(error, task, longStacks) {
  if (longStacks &&
      task.stack &&
      typeof error === 'object' &&
      error !== null) {
    // Note: IE sets error.stack when throwing but does not override a defined .stack.
    error.stack = filterFlushStack(error.stack) + task.stack;
  }

  if ('onError' in task) {
    task.onError(error);
  } else if (hasSetImmediate) {
    setImmediate(() => { throw error; });
  } else {
    setTimeout(() => { throw error; }, 0);
  }
}

/**
* Either a Function or a class with a call method that will do work when dequeued.
*/
interface Task {
  /**
  * Call it.
  */
  call(): void;
}

/**
* Implements an asynchronous task queue.
*/
export class TaskQueue {
  /**
   * Whether the queue is in the process of flushing.
   */
  flushing = false;

  /**
   * Enables long stack traces for queued tasks.
   */
  longStacks = false;

  /**
  * Creates an instance of TaskQueue.
  */
  constructor() {
    this.microTaskQueue = [];
    this.microTaskQueueCapacity = 1024;
    this.taskQueue = [];

    if (FEATURE.mutationObserver) {
      this.requestFlushMicroTaskQueue = makeRequestFlushFromMutationObserver(() => this.flushMicroTaskQueue());
    } else {
      this.requestFlushMicroTaskQueue = makeRequestFlushFromTimer(() => this.flushMicroTaskQueue());
    }

    this.requestFlushTaskQueue = makeRequestFlushFromTimer(() => this.flushTaskQueue());
  }

  /**
  * Immediately flushes the queue.
  * @param queue The task queue or micro task queue
  * @param capacity For periodically shift 1024 MicroTasks off the queue
  */
  _flushQueue(queue, capacity): void {
    let index = 0;
    let task;

    try {
      this.flushing = true;
      while (index < queue.length) {
        task = queue[index];
        if (this.longStacks) {
          this.stack = typeof task.stack === 'string' ? task.stack : undefined;
        }
        task.call();
        index++;

        // Prevent leaking memory for long chains of recursive calls to `queueMicroTask`.
        // If we call `queueMicroTask` within a MicroTask scheduled by `queueMicroTask`, the queue will
        // grow, but to avoid an O(n) walk for every MicroTask we execute, we don't
        // shift MicroTasks off the queue after they have been executed.
        // Instead, we periodically shift 1024 MicroTasks off the queue.
        if (capacity && index > capacity) {
          // Manually shift all values starting at the index back to the
          // beginning of the queue.
          for (let scan = 0, newLength = queue.length - index; scan < newLength; scan++) {
            queue[scan] = queue[scan + index];
          }

          queue.length -= index;
          index = 0;
        }
      }
    } catch (error) {
      onError(error, task, this.longStacks);
    } finally {
      this.flushing = false;
    }

    queue.length = 0;
  }

  /**
  * Queues a task on the micro task queue for ASAP execution.
  * @param task The task to queue up for ASAP execution.
  */
  queueMicroTask(task: Task | Function): void {
    if (this.microTaskQueue.length < 1) {
      this.requestFlushMicroTaskQueue();
    }

    if (this.longStacks) {
      task.stack = this.prepareQueueStack(microStackSeparator);
    }
    this.microTaskQueue.push(task);
  }

  /**
  * Queues a task on the macro task queue for turn-based execution.
  * @param task The task to queue up for turn-based execution.
  */
  queueTask(task: Task | Function): void {
    if (this.taskQueue.length < 1) {
      this.requestFlushTaskQueue();
    }

    if (this.longStacks) {
      task.stack = this.prepareQueueStack(stackSeparator);
    }
    this.taskQueue.push(task);
  }

  /**
  * Immediately flushes the task queue.
  */
  flushTaskQueue(): void {
    let queue = this.taskQueue;
    this.taskQueue = []; //recursive calls to queueTask should be scheduled after the next cycle

    this._flushQueue(queue);
  }

  /**
  * Immediately flushes the micro task queue.
  */
  flushMicroTaskQueue(): void {
    let queue = this.microTaskQueue;
    let capacity = this.microTaskQueueCapacity;

    this._flushQueue(queue, capacity);

    queue.length = 0;
  }

  prepareQueueStack(separator) {
    let stack = separator + filterQueueStack(captureStack());
    if (typeof this.stack === 'string') {
      stack = filterFlushStack(stack) + this.stack;
    }
    return stack;
  }
}

function captureStack() {
  let error = new Error();
  // Firefox, Chrome, Edge all have .stack defined by now, IE has not.
  if (error.stack) {
    return error.stack;
  }

  try {
    throw error;
  } catch (e) {
    return e.stack;
  }
}

function filterQueueStack(stack) {
  // Remove everything (error message + top stack frames) up to the topmost queueTask or queueMicroTask call
  return stack.replace(/^[\s\S]*?\bqueue(Micro)?Task\b[^\n]*\n/, '');
}

function filterFlushStack(stack) {
  // Remove bottom frames starting with the last flushTaskQueue or flushMicroTaskQueue
  let index = stack.lastIndexOf('flushMicroTaskQueue');
  if (index < 0) {
    index = stack.lastIndexOf('flushTaskQueue');
    if (index < 0) {
      return stack;
    }
  }
  index = stack.lastIndexOf('\n', index);
  return index < 0 ? stack : stack.substr(0, index);
  // The following would work but without regex support to match from end of string,
  // it's hard to ensure we have the last occurence of "flushTaskQueue".
  // return stack.replace(/\n[^\n]*?\bflush(Micro)?TaskQueue\b[\s\S]*$/, "");
}
<commit_msg>perf(index): remove capacity defined check<commit_after>import {DOM, FEATURE} from 'aurelia-pal';

let hasSetImmediate = typeof setImmediate === 'function';
const stackSeparator = '\nEnqueued in TaskQueue by:\n';
const microStackSeparator = '\nEnqueued in MicroTaskQueue by:\n';

function makeRequestFlushFromMutationObserver(flush) {
  let toggle = 1;
  let observer = DOM.createMutationObserver(flush);
  let node = DOM.createTextNode('');
  observer.observe(node, {characterData: true});
  return function requestFlush() {
    toggle = -toggle;
    node.data = toggle;
  };
}

function makeRequestFlushFromTimer(flush) {
  return function requestFlush() {
    // We dispatch a timeout with a specified delay of 0 for engines that
    // can reliably accommodate that request. This will usually be snapped
    // to a 4 milisecond delay, but once we're flushing, there's no delay
    // between events.
    let timeoutHandle = setTimeout(handleFlushTimer, 0);
    // However, since this timer gets frequently dropped in Firefox
    // workers, we enlist an interval handle that will try to fire
    // an event 20 times per second until it succeeds.
    let intervalHandle = setInterval(handleFlushTimer, 50);
    function handleFlushTimer() {
      // Whichever timer succeeds will cancel both timers and request the
      // flush.
      clearTimeout(timeoutHandle);
      clearInterval(intervalHandle);
      flush();
    }
  };
}

function onError(error, task, longStacks) {
  if (longStacks &&
      task.stack &&
      typeof error === 'object' &&
      error !== null) {
    // Note: IE sets error.stack when throwing but does not override a defined .stack.
    error.stack = filterFlushStack(error.stack) + task.stack;
  }

  if ('onError' in task) {
    task.onError(error);
  } else if (hasSetImmediate) {
    setImmediate(() => { throw error; });
  } else {
    setTimeout(() => { throw error; }, 0);
  }
}

/**
* Either a Function or a class with a call method that will do work when dequeued.
*/
interface Task {
  /**
  * Call it.
  */
  call(): void;
}

/**
* Implements an asynchronous task queue.
*/
export class TaskQueue {
  /**
   * Whether the queue is in the process of flushing.
   */
  flushing = false;

  /**
   * Enables long stack traces for queued tasks.
   */
  longStacks = false;

  /**
  * Creates an instance of TaskQueue.
  */
  constructor() {
    this.microTaskQueue = [];
    this.microTaskQueueCapacity = 1024;
    this.taskQueue = [];

    if (FEATURE.mutationObserver) {
      this.requestFlushMicroTaskQueue = makeRequestFlushFromMutationObserver(() => this.flushMicroTaskQueue());
    } else {
      this.requestFlushMicroTaskQueue = makeRequestFlushFromTimer(() => this.flushMicroTaskQueue());
    }

    this.requestFlushTaskQueue = makeRequestFlushFromTimer(() => this.flushTaskQueue());
  }

  /**
  * Immediately flushes the queue.
  * @param queue The task queue or micro task queue
  * @param capacity For periodically shift 1024 MicroTasks off the queue
  */
  _flushQueue(queue, capacity): void {
    let index = 0;
    let task;

    try {
      this.flushing = true;
      while (index < queue.length) {
        task = queue[index];
        if (this.longStacks) {
          this.stack = typeof task.stack === 'string' ? task.stack : undefined;
        }
        task.call();
        index++;

        // Prevent leaking memory for long chains of recursive calls to `queueMicroTask`.
        // If we call `queueMicroTask` within a MicroTask scheduled by `queueMicroTask`, the queue will
        // grow, but to avoid an O(n) walk for every MicroTask we execute, we don't
        // shift MicroTasks off the queue after they have been executed.
        // Instead, we periodically shift 1024 MicroTasks off the queue.
        if (index > capacity) {
          // Manually shift all values starting at the index back to the
          // beginning of the queue.
          for (let scan = 0, newLength = queue.length - index; scan < newLength; scan++) {
            queue[scan] = queue[scan + index];
          }

          queue.length -= index;
          index = 0;
        }
      }
    } catch (error) {
      onError(error, task, this.longStacks);
    } finally {
      this.flushing = false;
    }
  }

  /**
  * Queues a task on the micro task queue for ASAP execution.
  * @param task The task to queue up for ASAP execution.
  */
  queueMicroTask(task: Task | Function): void {
    if (this.microTaskQueue.length < 1) {
      this.requestFlushMicroTaskQueue();
    }

    if (this.longStacks) {
      task.stack = this.prepareQueueStack(microStackSeparator);
    }

    this.microTaskQueue.push(task);
  }

  /**
  * Queues a task on the macro task queue for turn-based execution.
  * @param task The task to queue up for turn-based execution.
  */
  queueTask(task: Task | Function): void {
    if (this.taskQueue.length < 1) {
      this.requestFlushTaskQueue();
    }

    if (this.longStacks) {
      task.stack = this.prepareQueueStack(stackSeparator);
    }

    this.taskQueue.push(task);
  }

  /**
  * Immediately flushes the task queue.
  */
  flushTaskQueue(): void {
    let queue = this.taskQueue;
    this.taskQueue = []; //recursive calls to queueTask should be scheduled after the next cycle
    this._flushQueue(queue, Number.MAX_VALUE);
  }

  /**
  * Immediately flushes the micro task queue.
  */
  flushMicroTaskQueue(): void {
    let queue = this.microTaskQueue;
    this._flushQueue(queue, this.microTaskQueueCapacity);
    queue.length = 0;
  }

  prepareQueueStack(separator) {
    let stack = separator + filterQueueStack(captureStack());

    if (typeof this.stack === 'string') {
      stack = filterFlushStack(stack) + this.stack;
    }

    return stack;
  }
}

function captureStack() {
  let error = new Error();

  // Firefox, Chrome, Edge all have .stack defined by now, IE has not.
  if (error.stack) {
    return error.stack;
  }

  try {
    throw error;
  } catch (e) {
    return e.stack;
  }
}

function filterQueueStack(stack) {
  // Remove everything (error message + top stack frames) up to the topmost queueTask or queueMicroTask call
  return stack.replace(/^[\s\S]*?\bqueue(Micro)?Task\b[^\n]*\n/, '');
}

function filterFlushStack(stack) {
  // Remove bottom frames starting with the last flushTaskQueue or flushMicroTaskQueue
  let index = stack.lastIndexOf('flushMicroTaskQueue');

  if (index < 0) {
    index = stack.lastIndexOf('flushTaskQueue');
    if (index < 0) {
      return stack;
    }
  }

  index = stack.lastIndexOf('\n', index);

  return index < 0 ? stack : stack.substr(0, index);
  // The following would work but without regex support to match from end of string,
  // it's hard to ensure we have the last occurence of "flushTaskQueue".
  // return stack.replace(/\n[^\n]*?\bflush(Micro)?TaskQueue\b[\s\S]*$/, "");
}
<|endoftext|>


<commit_before>import React from 'react';
import { Router, Route, IndexRoute } from 'react-router'
import { Provider } from 'react-redux';
import ReactDOM from 'react-dom';
import store, { history } from './store/configure-store'
import { fetchMatches } from './actions/matches-actions'
import { checkIfLoggedIn } from './actions/user-actions'
import MatchList from './components/MatchList'
import App from './components/App';
import LoginPage from './components/LoginPage'
import MatchDetail from './components/MatchDetail'
import UserProfile from './components/UserProfile'
import './styles/index.css';

store.dispatch(fetchMatches())
store.dispatch(checkIfLoggedIn())

const Root = () => {
  return (
    <Provider store={store}>
      <Router history={history}>
        <Route path="/" component={App} >
          <IndexRoute component={MatchList} />
          <Route path="/login" component={LoginPage} />
          <Route path="/matches/:matchId" component={MatchDetail} />
          <Route path="/profile" component={UserProfile} />
        </Route>
      </Router>
    </Provider>
  )
}

ReactDOM.render(
  <Root />,
  document.getElementById('root')
);
<commit_msg>routing for admin page<commit_after>import React from 'react';
import { Router, Route, IndexRoute } from 'react-router'
import { Provider } from 'react-redux';
import ReactDOM from 'react-dom';
import store, { history } from './store/configure-store'
import { fetchMatches } from './actions/matches-actions'
import { checkIfLoggedIn } from './actions/user-actions'
import MatchList from './components/MatchList'
import App from './components/App';
import LoginPage from './components/LoginPage'
import MatchDetail from './components/MatchDetail'
import UserProfile from './components/UserProfile'
import Admin from './components/Admin'
import './styles/index.css';

store.dispatch(fetchMatches())
store.dispatch(checkIfLoggedIn())

const Root = () => {
  return (
    <Provider store={store}>
      <Router history={history}>
        <Route path="/" component={App} >
          <IndexRoute component={MatchList} />
          <Route path="/login" component={LoginPage} />
          <Route path="/matches/:matchId" component={MatchDetail} />
          <Route path="/profile" component={UserProfile} />
          <Route path="/admin" component={Admin} />
        </Route>
      </Router>
    </Provider>
  )
}

ReactDOM.render(
  <Root />,
  document.getElementById('root')
);
<|endoftext|>


<commit_before>// jquery!
window.$ = window.jQuery = require("jquery");

/////////
// APP //
/////////
var App = function(){
	this.users = null;
	this.selectedUserIdx = null;
	this.selectedUser = null;
	this.projects = null;
	this.selectedProjectIdx = null;
	this.selectedProject = null;
	this.selectedFile = null;
};

App.prototype.login = function(key, user, rememberMe){
	// TODO: prevent from re-submitting while AJAX is running
	// TODO: clear existing data in next stages (they might change users and invalidate existing project data)

	if(rememberMe){
		// save login details to local storage
		window.localStorage.setItem("key", key);
		window.localStorage.setItem("rememberMe", "1");
	}else{
		// clear loging details from local storage
		window.localStorage.setItem("key", "");
		window.localStorage.setItem("rememberMe", "0");
	}

	$.ajax({
		url: "https://itch.io/api/1/"+key+"/my-games"
	}).done(function(data){
		console.log(data);

		if(data.errors){
			// error when submitting API key
			// TODO: fail and notify
		}

		if(data.games.length <= 0){
			// the user has nothing associated with their key
			// TODO: fail and notify
		}

		// find all usernames associated with key by stripping URLs
		var users={};
		for(var i = 0; i < data.games.length; ++i){
			var username = data.games[i].url.split("https://")[1].split(".itch.io/")[0];
			if(!users[username]){
				users[username] = {
					username: username,
					projects:[]
				}
			}
			users[username].projects.push(data.games[i]);
		}

		// add users to internal list + dropdown
		this.users = [];
		var s="";
		var i = 0;
		for(var u in users){
			this.users.push(users[u]);
			s += "<option value=\"" + (i++) + "\">" + users[u].username + "</option>";
		}
		$("#userSelect").html(s);

		// update section display
		$("section#login").hide();
		$("section#logout").show();

		// auto-select the first user in the dropdown
		// (provides a bit of feedback + removes the need for a null entry)
		$("#userSelect").val("0").change();

		$("section#selectUser").show();
	}.bind(this)).fail(function(){
		// couldn't get a response
		// TODO: fail and notify
		console.error("something went wrong!");
	}.bind(this));
};

App.prototype.logout = function(){
	$("section#login").show();

	$("#selectedFile").html("no .zip selected…");

	$("section#logout").hide();
	$("section#selectProject").hide();
	$("section#selectBuild").hide();
	$("section#selectUser").hide();
	$("section#butler").hide();
};
App.prototype.selectUser = function(idx){
	this.selectedUserIdx = parseInt(idx,10);
	this.selectedUser = this.users[this.selectedUserIdx];

	// update link
	$("#userPreview").attr("href", "https://"+this.selectedUser.username+".itch.io");

	// add the users games to the dropdown
	this.projects = this.selectedUser.projects;
	s="";
	for(var i = 0; i < this.projects.length; ++i){
		var g = this.projects[i];
		s += "<option value=\"" + i + "\">" + g.title + "</option>";
	}
	$("#projectSelect").html(s);

	// auto-select the first game in the dropdown
	// (provides a bit of feedback + removes the need for a null entry)
	$("#projectSelect").val("0").change();

	$("#selectProject").show();
};
App.prototype.selectProject = function(idx){
	this.selectedProjectIdx = parseInt(idx,10);
	this.selectedProject = this.projects[this.selectedProjectIdx];

	// get rid of the old cover, then set then new one
	$("#projectCover").attr("src", "");
	$("#projectCover").attr("src", this.selectedProject.cover_url);

	// update text
	$("#projectTitle").text(this.selectedProject.title);
	$("#projectText").text(this.selectedProject.short_text);

	// update link
	$("#projectUrl").attr("href", this.selectedProject.url);

	$("#selectBuild").show();
};
App.prototype.selectFile = function(){
	// prompt user to select a .zip archive
	remote.dialog.showOpenDialog(
	{
		title: "Select build archive",
		filters: [{name: "Build Archive", extensions:["zip"]}],
		properties: ["openFile"]
	},
	function(filenames){
		if(filenames.length==1){
			this.selectedFile = filenames[0];
			$("#selectedFile").text(this.selectedFile);
			$("section#butler").show();
		}else{
			// canceled selection
			$("section#butler").hide();
		}
	}.bind(this));
};
App.prototype.getChannels = function(){
	var channels = "";

	// add preset channels
	if($("#channelWin")[0].checked){
		channels += "win-";
	}if($("#channelOsx")[0].checked){
		channels += "osx-";
	}if($("#channelLinux")[0].checked){
		channels += "linux-";
	}

	// add custom channels
	channels += $("#channelOther").val();

	// remove the last dash
	if(channels.substr(-1) == "-"){
		channels = channels.slice(0,-1);
	}

	return channels;
};
App.prototype.getProjectShortUrl = function(){
	// the URL for butler is the same as the one for the project's the itch page
	return this.selectedProject.url.split(".itch.io/")[1];
};
App.prototype.getProjectUrl = function(){
	// butler URLs are user/project-url:channels-in-a-dash-separated-list
	return this.selectedUser.username+"/"+this.getProjectShortUrl()+":"+this.getChannels();
};

App.prototype.validate = function(){
	var s=this.getProjectUrl();
	$("#targetPreview").val(s);

	if(this.getChannels() <= 0){
		$("#btnPush").prop("disabled",true);
		$("#btnCheckStatus").prop("disabled",true);
	}else{
		$("#btnPush").prop("disabled",false);
		$("#btnCheckStatus").prop("disabled",false);
	}
}

////////////
// BUTLER //
////////////

var Butler = function(){
	this.process = "butler";
	this.busy = false;
};
Butler.prototype.call = function(args){
	if(this.busy){
		alert("butler's already running a process; quit being impatient");
		return;
	}

	this.busy = true;
		$("#output").text("");
	var child = spawn(this.process, args);

	child.stdout.on("data", this.onData.bind(this));
	child.stderr.on("data", this.onError.bind(this));
	child.on("close", this.onClose.bind(this));
};

Butler.prototype.push = function(file, url){
	this.call(["push", file, url]);
};
Butler.prototype.status = function(url){
	this.call(["status", url]);
};

Butler.prototype.onData = function(data){
	var s = data.toString();

	s = s.replace(/\n/g, "
");
	s = s.replace(/ /g, " ");

	s = $("#output").html() + s;

	var a = s.split("\r");
	s = "";
	while(a.length > 1){
		var c = a.shift();
		s += c.substr(0, c.lastIndexOf("
")+4);
	}
	s += a.shift();

	/*for(var i = 0; i < data.length; ++i){
		var c = String.fromCodePoint(data[i]);
		console.log(data[i], c);
		if(c == "\n"){
			s += "
";
		}if(c == " "){
			s += " ";
		}else if(c == "\r"){
			s = s.substring(0, s.lastIndexOf("
"))+"
";
		}else{
			s += c;
		}
	}*/
	$("#output").html(s);
	$("#output").scrollTop($("#output")[0].scrollHeight);
};
Butler.prototype.onError = function(data){
	this.onData(data);
};
Butler.prototype.onClose = function(code){
	console.log("child process exited with code "+code);
	this.busy = false;
};

$(document).ready(function(){

	var app = new App();
	var butler = new Butler();

	// get some of the stuff we need for later
	remote = require("electron").remote;
	spawn = require("child_process").spawn;

    // open links externally by default
    // since we're using a single-page frameless app, opening them in electron would be pretty weird
	var shell = require("electron").shell;
    $(document).on("click", "a[href^=\"http\"]", function(event) {
        event.preventDefault();
        shell.openExternal(this.href);
    });

    ///////////////////
    // FRAME BUTTONS //
    ///////////////////
	var win = remote.getCurrentWindow();

	win.on("maximize", function(){
		$("html").addClass("maximized");
	});
	win.on("unmaximize", function(){
		$("html").removeClass("maximized");
	});

	$("#btnMinimize").on("click",function(event){
		win.minimize();
	});
	$("#btnMaximize").on("click",function(event){
		if(win.isMaximized()){
			win.unmaximize();
		}else{
			win.maximize();
		}
	});
	$("#btnExit").on("click",function(event){
		remote.app.exit();
	});

	////////////////
	// MAIN STUFF //
	////////////////
	$("#channelWin,#channelOsx,#channelLinux,#channelOther").on("change",function(event){
		app.validate();
	});

	$("#btnLogin").on("click", function(event){
		app.login(
			$("#key").val(),
			$("#user").val(),
			$("#rememberMe")[0].checked
		);
	});

	$("#btnLogout").on("click", function(event){
		app.logout();
	});

	// get login details
	$("#key").val(window.localStorage.getItem("key"));
	if(window.localStorage.getItem("rememberMe") == "1"){
		$("#rememberMe").prop("checked", true);
		$("#login button").trigger("click");
	}

	$("#userSelect").on("change", function(event){
		app.selectUser($("#userSelect option:selected").val());
	});

	$("#projectSelect").on("change", function(event){
		app.selectProject($("#projectSelect option:selected").val());
		app.validate();
	});

	$("#selectedFile").on("click", function(event){
		app.selectFile();
	});

	$("#btnPush").on("click",function(event){
	 	butler.push(
	 		$("#selectedFile").text(),
	 		app.getProjectUrl()
	 	);
	});

	$("#btnCheckStatus").on("click",function(event){
	 	butler.status(app.getProjectUrl());
	});
});<commit_msg>basic error handling on failed login<commit_after>// jquery!
window.$ = window.jQuery = require("jquery");

/////////
// APP //
/////////
var App = function(){
	this.users = null;
	this.selectedUserIdx = null;
	this.selectedUser = null;
	this.projects = null;
	this.selectedProjectIdx = null;
	this.selectedProject = null;
	this.selectedFile = null;
};

App.prototype.login = function(key, user, rememberMe){
	// TODO: prevent from re-submitting while AJAX is running
	// TODO: clear existing data in next stages (they might change users and invalidate existing project data)

	if(rememberMe){
		// save login details to local storage
		window.localStorage.setItem("key", key);
		window.localStorage.setItem("rememberMe", "1");
	}else{
		// clear loging details from local storage
		window.localStorage.setItem("key", "");
		window.localStorage.setItem("rememberMe", "0");
	}

	$.ajax({
		url: "https://itch.io/api/1/"+key+"/my-games"
	}).done(function(data){
		console.log(data);

		// error handling

		if(data.errors){
			// error when submitting API key

			alert(data.errors.toString());

			return;
		}

		if(data.games.length <= 0){
			// the user has nothing associated with their key

			alert("Error: couldn't find any projects associated with this key. gui-butler can only push builds to existing projects; you need to use itch.io to actually create them.");

			return;
		}

		// success!
		// find all usernames associated with key by stripping URLs
		var users={};
		for(var i = 0; i < data.games.length; ++i){
			var username = data.games[i].url.split("https://")[1].split(".itch.io/")[0];
			if(!users[username]){
				users[username] = {
					username: username,
					projects:[]
				}
			}
			users[username].projects.push(data.games[i]);
		}

		// add users to internal list + dropdown
		this.users = [];
		var s="";
		var i = 0;
		for(var u in users){
			this.users.push(users[u]);
			s += "<option value=\"" + (i++) + "\">" + users[u].username + "</option>";
		}
		$("#userSelect").html(s);

		// update section display
		$("section#login").hide();
		$("section#logout").show();

		// auto-select the first user in the dropdown
		// (provides a bit of feedback + removes the need for a null entry)
		$("#userSelect").val("0").change();

		$("section#selectUser").show();
	}.bind(this)).fail(function(){
		// couldn't get a response
		alert("Error: itch.io failed to respond. Check your internet connection etc.");
	}.bind(this));
};

App.prototype.logout = function(){
	$("section#login").show();

	$("#selectedFile").html("no .zip selected…");

	$("section#logout").hide();
	$("section#selectProject").hide();
	$("section#selectBuild").hide();
	$("section#selectUser").hide();
	$("section#butler").hide();
};
App.prototype.selectUser = function(idx){
	this.selectedUserIdx = parseInt(idx,10);
	this.selectedUser = this.users[this.selectedUserIdx];

	// update link
	$("#userPreview").attr("href", "https://"+this.selectedUser.username+".itch.io");

	// add the users games to the dropdown
	this.projects = this.selectedUser.projects;
	s="";
	for(var i = 0; i < this.projects.length; ++i){
		var g = this.projects[i];
		s += "<option value=\"" + i + "\">" + g.title + "</option>";
	}
	$("#projectSelect").html(s);

	// auto-select the first game in the dropdown
	// (provides a bit of feedback + removes the need for a null entry)
	$("#projectSelect").val("0").change();

	$("#selectProject").show();
};
App.prototype.selectProject = function(idx){
	this.selectedProjectIdx = parseInt(idx,10);
	this.selectedProject = this.projects[this.selectedProjectIdx];

	// get rid of the old cover, then set then new one
	$("#projectCover").attr("src", "");
	$("#projectCover").attr("src", this.selectedProject.cover_url);

	// update text
	$("#projectTitle").text(this.selectedProject.title);
	$("#projectText").text(this.selectedProject.short_text);

	// update link
	$("#projectUrl").attr("href", this.selectedProject.url);

	$("#selectBuild").show();
};
App.prototype.selectFile = function(){
	// prompt user to select a .zip archive
	remote.dialog.showOpenDialog(
	{
		title: "Select build archive",
		filters: [{name: "Build Archive", extensions:["zip"]}],
		properties: ["openFile"]
	},
	function(filenames){
		if(filenames.length==1){
			this.selectedFile = filenames[0];
			$("#selectedFile").text(this.selectedFile);
			$("section#butler").show();
		}else{
			// canceled selection
			$("section#butler").hide();
		}
	}.bind(this));
};
App.prototype.getChannels = function(){
	var channels = "";

	// add preset channels
	if($("#channelWin")[0].checked){
		channels += "win-";
	}if($("#channelOsx")[0].checked){
		channels += "osx-";
	}if($("#channelLinux")[0].checked){
		channels += "linux-";
	}

	// add custom channels
	channels += $("#channelOther").val();

	// remove the last dash
	if(channels.substr(-1) == "-"){
		channels = channels.slice(0,-1);
	}

	return channels;
};
App.prototype.getProjectShortUrl = function(){
	// the URL for butler is the same as the one for the project's the itch page
	return this.selectedProject.url.split(".itch.io/")[1];
};
App.prototype.getProjectUrl = function(){
	// butler URLs are user/project-url:channels-in-a-dash-separated-list
	return this.selectedUser.username+"/"+this.getProjectShortUrl()+":"+this.getChannels();
};

App.prototype.validate = function(){
	var s=this.getProjectUrl();
	$("#targetPreview").val(s);

	if(this.getChannels() <= 0){
		$("#btnPush").prop("disabled",true);
		$("#btnCheckStatus").prop("disabled",true);
	}else{
		$("#btnPush").prop("disabled",false);
		$("#btnCheckStatus").prop("disabled",false);
	}
}

////////////
// BUTLER //
////////////

var Butler = function(){
	this.process = "butler";
	this.busy = false;
};
Butler.prototype.call = function(args){
	if(this.busy){
		alert("butler's already running a process; quit being impatient");
		return;
	}

	this.busy = true;
		$("#output").text("");
	var child = spawn(this.process, args);

	child.stdout.on("data", this.onData.bind(this));
	child.stderr.on("data", this.onError.bind(this));
	child.on("close", this.onClose.bind(this));
};

Butler.prototype.push = function(file, url){
	this.call(["push", file, url]);
};
Butler.prototype.status = function(url){
	this.call(["status", url]);
};

Butler.prototype.onData = function(data){
	var s = data.toString();

	s = s.replace(/\n/g, "
");
	s = s.replace(/ /g, " ");

	s = $("#output").html() + s;

	var a = s.split("\r");
	s = "";
	while(a.length > 1){
		var c = a.shift();
		s += c.substr(0, c.lastIndexOf("
")+4);
	}
	s += a.shift();

	/*for(var i = 0; i < data.length; ++i){
		var c = String.fromCodePoint(data[i]);
		console.log(data[i], c);
		if(c == "\n"){
			s += "
";
		}if(c == " "){
			s += " ";
		}else if(c == "\r"){
			s = s.substring(0, s.lastIndexOf("
"))+"
";
		}else{
			s += c;
		}
	}*/
	$("#output").html(s);
	$("#output").scrollTop($("#output")[0].scrollHeight);
};
Butler.prototype.onError = function(data){
	this.onData(data);
};
Butler.prototype.onClose = function(code){
	console.log("child process exited with code "+code);
	this.busy = false;
};

$(document).ready(function(){

	var app = new App();
	var butler = new Butler();

	// get some of the stuff we need for later
	remote = require("electron").remote;
	spawn = require("child_process").spawn;

    // open links externally by default
    // since we're using a single-page frameless app, opening them in electron would be pretty weird
	var shell = require("electron").shell;
    $(document).on("click", "a[href^=\"http\"]", function(event) {
        event.preventDefault();
        shell.openExternal(this.href);
    });

    ///////////////////
    // FRAME BUTTONS //
    ///////////////////
	var win = remote.getCurrentWindow();

	win.on("maximize", function(){
		$("html").addClass("maximized");
	});
	win.on("unmaximize", function(){
		$("html").removeClass("maximized");
	});

	$("#btnMinimize").on("click",function(event){
		win.minimize();
	});
	$("#btnMaximize").on("click",function(event){
		if(win.isMaximized()){
			win.unmaximize();
		}else{
			win.maximize();
		}
	});
	$("#btnExit").on("click",function(event){
		remote.app.exit();
	});

	////////////////
	// MAIN STUFF //
	////////////////
	$("#channelWin,#channelOsx,#channelLinux,#channelOther").on("change",function(event){
		app.validate();
	});

	$("#btnLogin").on("click", function(event){
		app.login(
			$("#key").val(),
			$("#user").val(),
			$("#rememberMe")[0].checked
		);
	});

	$("#btnLogout").on("click", function(event){
		app.logout();
	});

	// get login details
	$("#key").val(window.localStorage.getItem("key"));
	if(window.localStorage.getItem("rememberMe") == "1"){
		$("#rememberMe").prop("checked", true);

		// auto-login
		$("#login button").trigger("click");
	}

	$("#userSelect").on("change", function(event){
		app.selectUser($("#userSelect option:selected").val());
	});

	$("#projectSelect").on("change", function(event){
		app.selectProject($("#projectSelect option:selected").val());
		app.validate();
	});

	$("#selectedFile").on("click", function(event){
		app.selectFile();
	});

	$("#btnPush").on("click",function(event){
	 	butler.push(
	 		$("#selectedFile").text(),
	 		app.getProjectUrl()
	 	);
	});

	$("#btnCheckStatus").on("click",function(event){
	 	butler.status(app.getProjectUrl());
	});
});<|endoftext|>


<commit_before>import 'babel-core/register';
import 'babel-polyfill';
import express from 'express';
import request from 'request-promise';
import bodyParser from 'body-parser';
import _debug from 'debug';
import human2date from 'date.js';
import config from '../config.json';
import { formatDate } from './utils';

const INCOMING_WEBHOOK_URL = config.slack.incomingWebhookURL;

const debug = _debug('pledge');

const postOnSlack = json => request({
  json,
  url: INCOMING_WEBHOOK_URL,
  method: 'POST'
});

const app = express();

app.use(bodyParser.urlencoded({ extended: false }));

app.post('/newPledge', async ({ body: { text, user_name } }, res) => {
  try {
    debug({ text, user_name });
    const [, performer, pledge, deadline] = /(@[a-zA-Z0-9]+) (.+) by (.+)/.exec(text.trim()) || [];

    if (!performer) {
      throw new Error('"Username" is missing. (@username [what] by [when])');
    } else if (!pledge) {
      throw new Error('"What" is missing. (@username [what] by [when])');
    } else if (!deadline) {
      throw new Error('"When" is missing. (@username [what] by [when])');
    }

    const parsedDeadline = human2date(deadline);

    if (parsedDeadline.getTime() < Date.now()) {
      throw new Error('"When" should be in the future');
    }

    const requester = `@${user_name}`;

    postOnSlack({
      text: `${requester} added a pledge: "${pledge} by ${deadline} (${formatDate(parsedDeadline)})"`,
      channel: performer,
      username: 'pledge',
      icon_emoji: ':dog:'
    });

    res.send(`Successfully added pledge: "${pledge} by ${deadline} (${formatDate(parsedDeadline)})"`);
  } catch (err) {
    debug(err);
    res.send(`Error: ${err.message}`);
  }
});

app.listen(3000);
<commit_msg>save new pledges in db<commit_after>import 'babel-core/register';
import 'babel-polyfill';
import express from 'express';
import request from 'request-promise';
import bodyParser from 'body-parser';
import _debug from 'debug';
import human2date from 'date.js';
import config from '../config.json';
import { formatDate } from './utils';
import * as db from './db';

const INCOMING_WEBHOOK_URL = config.slack.incomingWebhookURL;

const debug = _debug('pledge');

const postOnSlack = json => request({
  json,
  url: INCOMING_WEBHOOK_URL,
  method: 'POST'
});

const app = express();

app.use(bodyParser.urlencoded({ extended: false }));

app.post('/newPledge', async ({ body: { text, user_name } }, res) => {
  try {
    debug({ text, user_name });
    const [, performer, content, humanReadableDeadline] = /(@[a-zA-Z0-9]+) (.+) by (.+)/.exec(text.trim()) || [];

    if (!performer) {
      throw new Error('"Username" is missing. (@username [what] by [when])');
    } else if (!content) {
      throw new Error('"What" is missing. (@username [what] by [when])');
    } else if (!humanReadableDeadline) {
      throw new Error('"When" is missing. (@username [what] by [when])');
    }

    const deadline = human2date(humanReadableDeadline);

    if (deadline.getTime() < Date.now()) {
      throw new Error('"When" should be in the future');
    }

    const requester = `@${user_name}`;

    await db.insertPledge({ requester, performer, content, deadline });

    await postOnSlack({
      text: `${requester} added a pledge: "${content} by ${humanReadableDeadline} (${formatDate(deadline)})"`,
      channel: performer,
      username: 'pledge',
      icon_emoji: ':dog:'
    });

    res.send(`Successfully added pledge: "${content} by ${humanReadableDeadline} (${formatDate(deadline)})"`);
  } catch (err) {
    debug(err);
    res.send(`Error: ${err.message}`);
  }
});

app.listen(3000, db.init);
<|endoftext|>