<commit_before>var hoek = require('hoek');
var seq = require('seq');
var squel = require('squel');

function Persistence (db) {
    this._db = db;
}

Persistence.prototype.loadUsers = function (limitStatement, orderStatement, callback) {
    this._db.selectMany(this._createUserQuery(limitStatement).toString(), [], callback);
};

Persistence.prototype.loadUserById = function (userId, callback) {
    var query = this._createUserQuery()
        .where('users.id = ?', userId);

    var parametrized = query.toParam();

    this._db.selectOne(parametrized.text, parametrized.values, callback);
};

Persistence.prototype.loadUserByName = function (name, callback) {
    var query = this._createUserQuery()
        .where('lower(users.name) = ?', name.toLowerCase());

    var parametrized = query.toParam();

    this._db.selectOne(parametrized.text, parametrized.values, callback);
};

Persistence.prototype.createUser = function (name, callback) {
    var query = squel.insert()
        .into('users')
        .set('name', name);

    var parametrized = query.toParam();

    this._db.query(parametrized.text, parametrized.values, function (error, result) {
        if (error) return callback(error, null);

        callback(null, result.lastID);
    });
};

Persistence.prototype.createTransaction = function (userId, amount, callback) {
    var query = squel.insert()
        .into('transactions')
        .set('userId', userId)
        .set('value', amount);

    var parametrized = query.toParam();

    this._db.query(parametrized.text, parametrized.values, function (error, result) {
        if (error) return callback(error, null);

        callback(null, result.lastID);
    });
};

Persistence.prototype.loadTransaction = function (transactionId, callback) {
    var query = this._createTransactionQuery()
        .where('id = ?', transactionId);

    var parametrized = query.toParam();

    this._db.selectOne(parametrized.text, parametrized.values, callback);
};

Persistence.prototype.loadTransactionsByUserId = function (userId, limitStatement, orderStatement, callback) {
    var query = this._createTransactionQuery(limitStatement)
        .where('userId = ?', userId);

    var parametrized = query.toParam();

    this._db.selectMany(parametrized.text, parametrized.values, callback);
};

Persistence.prototype.loadMetrics = function (callback) {
    var that = this;
    var result = {};

    seq()
        .par(this._createMetricSubStep('select count(*) as countTransactions from transactions', result))
        .par(this._createMetricSubStep('select sum(value) as overallBalance from transactions', result))
        .par(this._createMetricSubStep('select count(*) as countUsers from users', result))
        .par(this._createMetricSubStep('select avg(userBalance) as avgBalance from (select sum(value) as userBalance from transactions group by userId) as ghoti', result))
        .par(function () {
            var done = this;
            that._db.selectMany('select date(createDate) as date, count(*) as overallNumber,count(distinct userid) as distinctUsers,sum(value) as dayBalance,sum(max(value, 0)) as dayBalancePositive,sum(min(value, 0)) as dayBalanceNegative from transactions where createDate >=  date("now", "-30 day") group by date(createDate);', [], function (error, transactions) {
                if (error) return done(error);

                result.days = transactions;
                done();
            });
        })
        .seq(function () {
            callback(null, result);
        })
        .catch(function (error) {
            callback(error, null);
        });
};

Persistence.prototype._createMetricSubStep = function (query, overallResult) {
    var that = this;

    return function () {
        var done = this;
        that._db.selectOne(query, [], function (error, result) {
            if (error) return done(error);

            hoek.merge(overallResult, result);
            done();
        });
    };
};

Persistence.prototype._createTransactionQuery = function (limitStatement) {
    var query = squel.select()
        .field('id')
        .field('userId')
        .field('createDate')
        .field('value')
        .from('transactions')
        .order('id', false);

    if (limitStatement) {
        query.offset(limitStatement.offset());
        query.limit(limitStatement.limit());
    }

    return query;
};

Persistence.prototype._createUserQuery = function (limitStatement) {
    var query = squel.select()
        .field('users.id', 'id')
        .field('users.name', 'name')
        .field('coalesce(sum(value),0)', 'balance')
        .field('max(transactions.createDate)', 'lastTransaction')
        .from('users')
        .left_join("transactions", null, "transactions.userId = users.id")
        .group('users.id');

    if (limitStatement) {
        query.offset(limitStatement.offset());
        query.limit(limitStatement.limit());
    }

    return query;
};

module.exports = Persistence;<commit_msg>refactors persistence<commit_after>var hoek = require('hoek');
var seq = require('seq');
var squel = require('squel');

function Persistence (db) {
    this._db = db;
}

Persistence.SELECT_ONE = 'One';
Persistence.SELECT_MANY = 'Many';

Persistence.prototype.loadUsers = function (limitStatement, orderStatement, callback) {
    this._queryMany(this._createUserQuery(limitStatement), callback);
};

Persistence.prototype.loadUserById = function (userId, callback) {
    this._queryOne(this._createUserQuery().where('users.id = ?', userId), callback);
};

Persistence.prototype.loadUserByName = function (name, callback) {
    this._queryOne(this._createUserQuery().where('lower(users.name) = ?', name.toLowerCase()), callback);
};

Persistence.prototype.createUser = function (name, callback) {
    var query = squel.insert()
        .into('users')
        .set('name', name);

    this._insert(query, callback);
};

Persistence.prototype.createTransaction = function (userId, amount, callback) {
    var query = squel.insert()
        .into('transactions')
        .set('userId', userId)
        .set('value', amount);

    this._insert(query, callback);
};

Persistence.prototype.loadTransactions = function(limitStatement, orderStatement, callback) {
    this._queryMany(this._createTransactionQuery(limitStatement), callback);
};

Persistence.prototype.loadTransaction = function (transactionId, callback) {
    this._queryOne(this._createTransactionQuery().where('id = ?', transactionId), callback);
};

Persistence.prototype.loadTransactionsByUserId = function (userId, limitStatement, orderStatement, callback) {
    this._queryMany(this._createTransactionQuery(limitStatement).where('userId = ?', userId), callback);
};

Persistence.prototype._insert = function(query, callback) {
    var parametrized = query.toParam();

    this._db.query(parametrized.text, parametrized.values, function (error, result) {
        if (error) return callback(error, null);

        callback(null, result.lastID);
    });
};

Persistence.prototype._queryOne = function(query, callback) {
    this._query(Persistence.SELECT_ONE, query, callback);
};

Persistence.prototype._queryMany = function(query, callback) {
    this._query(Persistence.SELECT_MANY, query, callback);
};

Persistence.prototype._query = function (type, query, callback) {
    var parametrized = query.toParam();

    this._db['select' + type].call(this._db, parametrized.text, parametrized.values, callback);
};

Persistence.prototype.loadMetrics = function (callback) {
    var that = this;
    var result = {};

    seq()
        .par(this._createMetricSubStep('select count(*) as countTransactions from transactions', result))
        .par(this._createMetricSubStep('select sum(value) as overallBalance from transactions', result))
        .par(this._createMetricSubStep('select count(*) as countUsers from users', result))
        .par(this._createMetricSubStep('select avg(userBalance) as avgBalance from (select sum(value) as userBalance from transactions group by userId) as ghoti', result))
        .par(function () {
            var done = this;
            that._db.selectMany('select date(createDate) as date, count(*) as overallNumber,count(distinct userid) as distinctUsers,sum(value) as dayBalance,sum(max(value, 0)) as dayBalancePositive,sum(min(value, 0)) as dayBalanceNegative from transactions where createDate >=  date("now", "-30 day") group by date(createDate);', [], function (error, transactions) {
                if (error) return done(error);

                result.days = transactions;
                done();
            });
        })
        .seq(callback.bind(null, null, result))
        .catch(function (error) {
            callback(error, null);
        });
};

Persistence.prototype._createMetricSubStep = function (query, overallResult) {
    var that = this;

    return function () {
        var done = this;
        that._db.selectOne(query, [], function (error, result) {
            if (error) return done(error);

            hoek.merge(overallResult, result);
            done();
        });
    };
};

Persistence.prototype._createTransactionQuery = function (limitStatement) {
    var query = squel.select()
        .field('id')
        .field('userId')
        .field('createDate')
        .field('value')
        .from('transactions')
        .order('id', false);

    if (limitStatement) {
        query.offset(limitStatement.offset());
        query.limit(limitStatement.limit());
    }

    return query;
};

Persistence.prototype._createUserQuery = function (limitStatement) {
    var query = squel.select()
        .field('users.id', 'id')
        .field('users.name', 'name')
        .field('coalesce(sum(value),0)', 'balance')
        .field('max(transactions.createDate)', 'lastTransaction')
        .from('users')
        .left_join('transactions', null, 'transactions.userId = users.id')
        .group('users.id');

    if (limitStatement) {
        query.offset(limitStatement.offset());
        query.limit(limitStatement.limit());
    }

    return query;
};

module.exports = Persistence;<|endoftext|>


<commit_before>import semver from "semver";

/**
 * Represents a node in a PackageGraph.
 * @constructor
 * @param {!<Package>} pkg - A Package object to build the node from.
 */
export class PackageGraphNode {
  constructor(pkg) {
    this.package = pkg;
    this.dependencies = [];
  }
}

/**
 * Represents a node in a PackageGraph.
 * @constructor
 * @param {!Array.<Package>} packages An array of Packages to build the graph out of.
 * @param {boolean} [depsOnly=false] True to create a graph of only dependencies, excluding the
 *    devDependencies that would normally be included.
 */
export default class PackageGraph {
  constructor(packages, depsOnly = false, versionParser) {
    this.nodes = [];
    this.nodesByName = {};

    for (let p = 0; p < packages.length; p++) {
      const pkg = packages[p];
      const node = new PackageGraphNode(pkg);
      this.nodes.push(node);
      this.nodesByName[pkg.name] = node;
    }

    for (let n = 0; n < this.nodes.length; n++) {
      const node = this.nodes[n];
      const dependencies = node.package[depsOnly ? "dependencies" : "allDependencies"] || {};
      const depNames = Object.keys(dependencies);

      for (let d = 0; d < depNames.length; d++) {
        const depName = depNames[d];
        const packageNode = this.nodesByName[depName];

        if (packageNode) {
          const depVersion = (versionParser
            ? versionParser.parseVersion(dependencies[depName]).version
            : dependencies[depName]
          );

          if (semver.satisfies(packageNode.package.version, depVersion)) {
            node.dependencies.push(depName);
          }
        }
      }
    }
  }

  get(packageName) {
    return this.nodesByName[packageName];
  }
}
<commit_msg>refactor: encapsulate semver comparison in PackageGraphNode<commit_after>import semver from "semver";

/**
 * Represents a node in a PackageGraph.
 * @constructor
 * @param {!<Package>} pkg - A Package object to build the node from.
 */
export class PackageGraphNode {
  constructor(pkg) {
    this.package = pkg;
    this.dependencies = [];
  }

  satisfies(versionRange) {
    return semver.satisfies(this.package.version, versionRange);
  }
}

/**
 * Represents a node in a PackageGraph.
 * @constructor
 * @param {!Array.<Package>} packages An array of Packages to build the graph out of.
 * @param {boolean} [depsOnly=false] True to create a graph of only dependencies, excluding the
 *    devDependencies that would normally be included.
 */
export default class PackageGraph {
  constructor(packages, depsOnly = false, versionParser) {
    this.nodes = [];
    this.nodesByName = {};

    for (let p = 0; p < packages.length; p++) {
      const pkg = packages[p];
      const node = new PackageGraphNode(pkg);
      this.nodes.push(node);
      this.nodesByName[pkg.name] = node;
    }

    for (let n = 0; n < this.nodes.length; n++) {
      const node = this.nodes[n];
      const dependencies = node.package[depsOnly ? "dependencies" : "allDependencies"] || {};
      const depNames = Object.keys(dependencies);

      for (let d = 0; d < depNames.length; d++) {
        const depName = depNames[d];
        const packageNode = this.nodesByName[depName];

        if (packageNode) {
          const depVersion = (versionParser
            ? versionParser.parseVersion(dependencies[depName]).version
            : dependencies[depName]
          );

          if (packageNode.satisfies(depVersion)) {
            node.dependencies.push(depName);
          }
        }
      }
    }
  }

  get(packageName) {
    return this.nodesByName[packageName];
  }
}
<|endoftext|>


<commit_before>/**
 * Copyright 2014-2015, Yahoo! Inc.
 * Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
 */
/*global window */
'use strict';

var debug = require('debug')('RouterMixin');
var navigateAction = require('../actions/navigate');
var History = require('./History');
var React = require('react');
var TYPE_CLICK = 'click';
var TYPE_PAGELOAD = 'pageload';
var TYPE_REPLACESTATE = 'replacestate';
var TYPE_POPSTATE = 'popstate';
var TYPE_DEFAULT = 'default'; // default value if navigation type is missing, for programmatic navigation
var RouterMixin;

require('setimmediate');

function routesEqual(route1, route2) {
    route1 = route1 || {};
    route2 = route2 || {};
    return (route1.url === route2.url);
}

function saveScrollPosition(e, history) {
    var historyState = (history.getState && history.getState()) || {};
    historyState.scroll = {x: window.scrollX, y: window.scrollY};
    debug('remember scroll position', historyState.scroll);
    history.replaceState(historyState);
}

RouterMixin = {
    contextTypes: {
        executeAction: React.PropTypes.func,
        makePath: React.PropTypes.func
    },
    childContextTypes: {
        makePath: React.PropTypes.func
    },
    getChildContext: function(){
        var context = {};
        Object.keys(RouterMixin.childContextTypes).forEach(function (key) {
            context[key] = (this.props.context && this.props.context[key]) || this.context[key];
        }, this);
        return context;
    },
    componentDidMount: function() {
        var self = this;
        var context;
        var urlFromHistory;
        var urlFromState;

        if (self.context && self.context.executeAction) {
            context = self.context;
        } else if (self.props.context && self.props.context.executeAction) {
            context = self.props.context;
        }

        self._history = ('function' === typeof self.props.historyCreator) ? self.props.historyCreator() : new History();
        self._enableScroll = (self.props.enableScroll !== false);

        if (self.props.checkRouteOnPageLoad) {
            // You probably want to enable checkRouteOnPageLoad, if you use a history implementation
            // that supports hash route:
            //   At page load, for browsers without pushState AND hash is present in the url,
            //   since hash fragment is not sent to the server side, we need to
            //   dispatch navigate action on browser side to load the actual page content
            //   for the route represented by the hash fragment.

            urlFromHistory = self._history.getUrl();
            urlFromState = self.state && self.state.route && self.state.route.url;

            if (context && (urlFromHistory !== urlFromState)) {
                // put it in setImmediate, because we need the base component to have
                // store listeners attached, before navigateAction is executed.
                debug('pageload navigate to actual route', urlFromHistory, urlFromState);
                setImmediate(function navigateToActualRoute() {
                    context.executeAction(navigateAction, {type: TYPE_PAGELOAD, url: urlFromHistory});
                });
            }
        }

        self._historyListener = function (e) {
            if (context) {
                var url = self._history.getUrl();
                debug('history listener invoked', e, url, self.state.route.url);
                if (url !== self.state.route.url) {
                    context.executeAction(navigateAction, {type: TYPE_POPSTATE, url: url, params: (e.state && e.state.params)});
                }
            }
        };
        self._history.on(self._historyListener);

        if (self._enableScroll) {
            var scrollTimer;
            self._scrollListener = function (e) {
                if (scrollTimer) {
                    window.clearTimeout(scrollTimer);
                }
                scrollTimer = window.setTimeout(saveScrollPosition.bind(self, e, self._history), 150);
            };
            window.addEventListener('scroll', self._scrollListener);
        }
    },
    componentWillUnmount: function() {
        this._history.off(this._historyListener);
        this._historyListener = null;

        if (this._enableScroll) {
            window.removeEventListener('scroll', this._scrollListener);
            this._scrollListener = null;
        }

        this._history = null;
    },
    componentDidUpdate: function (prevProps, prevState) {
        debug('component did update', prevState, this.state);

        var newState = this.state;
        if (routesEqual(prevState && prevState.route, newState && newState.route)) {
            return;
        }

        var nav = newState.route.navigate || {};
        var navType = nav.type || TYPE_DEFAULT;
        var historyState;
        var prevHistoryState;
        var pageTitle;

        function resetScrollPosition() {
            window.scrollTo(0, 0);
            historyState.scroll = {x: 0, y: 0};
            debug('on click navigation, reset scroll position to (0, 0)');
        }

        switch (navType) {
            case TYPE_CLICK:
            case TYPE_DEFAULT:
            case TYPE_REPLACESTATE:
                historyState = {params: (nav.params || {})};
                if(this._enableScroll) {
                    if (!nav.preserveScrollPosition) {
                        resetScrollPosition();
                    } else {
                        historyState.scroll = {x: window.scrollX, y: window.scrollY};
                    }
                }
                pageTitle = nav.params && nav.params.pageTitle || null;
                if(navType == TYPE_REPLACESTATE) {
                    this._history.replaceState(historyState, pageTitle, newState.route.url);
                } else {
                    this._history.pushState(historyState, pageTitle, newState.route.url);
                }
                break;
            case TYPE_POPSTATE:
                if (this._enableScroll) {
                    historyState = (this._history.getState && this._history.getState()) || {};
                    var scroll = (historyState && historyState.scroll) || {};
                    debug('on popstate navigation, restore scroll position to ', scroll);
                    window.scrollTo(scroll.x || 0, scroll.y || 0);
                }
                break;
        }
    }
};

module.exports = RouterMixin;
<commit_msg>remove resetScrollPosition function and unused variable<commit_after>/**
 * Copyright 2014-2015, Yahoo! Inc.
 * Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
 */
/*global window */
'use strict';

var debug = require('debug')('RouterMixin');
var navigateAction = require('../actions/navigate');
var History = require('./History');
var React = require('react');
var TYPE_CLICK = 'click';
var TYPE_PAGELOAD = 'pageload';
var TYPE_REPLACESTATE = 'replacestate';
var TYPE_POPSTATE = 'popstate';
var TYPE_DEFAULT = 'default'; // default value if navigation type is missing, for programmatic navigation
var RouterMixin;

require('setimmediate');

function routesEqual(route1, route2) {
    route1 = route1 || {};
    route2 = route2 || {};
    return (route1.url === route2.url);
}

function saveScrollPosition(e, history) {
    var historyState = (history.getState && history.getState()) || {};
    historyState.scroll = {x: window.scrollX, y: window.scrollY};
    debug('remember scroll position', historyState.scroll);
    history.replaceState(historyState);
}

RouterMixin = {
    contextTypes: {
        executeAction: React.PropTypes.func,
        makePath: React.PropTypes.func
    },
    childContextTypes: {
        makePath: React.PropTypes.func
    },
    getChildContext: function(){
        var context = {};
        Object.keys(RouterMixin.childContextTypes).forEach(function (key) {
            context[key] = (this.props.context && this.props.context[key]) || this.context[key];
        }, this);
        return context;
    },
    componentDidMount: function() {
        var self = this;
        var context;
        var urlFromHistory;
        var urlFromState;

        if (self.context && self.context.executeAction) {
            context = self.context;
        } else if (self.props.context && self.props.context.executeAction) {
            context = self.props.context;
        }

        self._history = ('function' === typeof self.props.historyCreator) ? self.props.historyCreator() : new History();
        self._enableScroll = (self.props.enableScroll !== false);

        if (self.props.checkRouteOnPageLoad) {
            // You probably want to enable checkRouteOnPageLoad, if you use a history implementation
            // that supports hash route:
            //   At page load, for browsers without pushState AND hash is present in the url,
            //   since hash fragment is not sent to the server side, we need to
            //   dispatch navigate action on browser side to load the actual page content
            //   for the route represented by the hash fragment.

            urlFromHistory = self._history.getUrl();
            urlFromState = self.state && self.state.route && self.state.route.url;

            if (context && (urlFromHistory !== urlFromState)) {
                // put it in setImmediate, because we need the base component to have
                // store listeners attached, before navigateAction is executed.
                debug('pageload navigate to actual route', urlFromHistory, urlFromState);
                setImmediate(function navigateToActualRoute() {
                    context.executeAction(navigateAction, {type: TYPE_PAGELOAD, url: urlFromHistory});
                });
            }
        }

        self._historyListener = function (e) {
            if (context) {
                var url = self._history.getUrl();
                debug('history listener invoked', e, url, self.state.route.url);
                if (url !== self.state.route.url) {
                    context.executeAction(navigateAction, {type: TYPE_POPSTATE, url: url, params: (e.state && e.state.params)});
                }
            }
        };
        self._history.on(self._historyListener);

        if (self._enableScroll) {
            var scrollTimer;
            self._scrollListener = function (e) {
                if (scrollTimer) {
                    window.clearTimeout(scrollTimer);
                }
                scrollTimer = window.setTimeout(saveScrollPosition.bind(self, e, self._history), 150);
            };
            window.addEventListener('scroll', self._scrollListener);
        }
    },
    componentWillUnmount: function() {
        this._history.off(this._historyListener);
        this._historyListener = null;

        if (this._enableScroll) {
            window.removeEventListener('scroll', this._scrollListener);
            this._scrollListener = null;
        }

        this._history = null;
    },
    componentDidUpdate: function (prevProps, prevState) {
        debug('component did update', prevState, this.state);

        var newState = this.state;
        if (routesEqual(prevState && prevState.route, newState && newState.route)) {
            return;
        }

        var nav = newState.route.navigate || {};
        var navType = nav.type || TYPE_DEFAULT;
        var historyState;
        var pageTitle;

        switch (navType) {
            case TYPE_CLICK:
            case TYPE_DEFAULT:
            case TYPE_REPLACESTATE:
                historyState = {params: (nav.params || {})};
                if(this._enableScroll) {
                    if (nav.preserveScrollPosition) {
                        historyState.scroll = {x: window.scrollX, y: window.scrollY};
                    } else {
                        window.scrollTo(0, 0);
                        historyState.scroll = {x: 0, y: 0};
                        debug('on click navigation, reset scroll position to (0, 0)');
                    }
                }
                pageTitle = nav.params && nav.params.pageTitle || null;
                if(navType == TYPE_REPLACESTATE) {
                    this._history.replaceState(historyState, pageTitle, newState.route.url);
                } else {
                    this._history.pushState(historyState, pageTitle, newState.route.url);
                }
                break;
            case TYPE_POPSTATE:
                if (this._enableScroll) {
                    historyState = (this._history.getState && this._history.getState()) || {};
                    var scroll = (historyState && historyState.scroll) || {};
                    debug('on popstate navigation, restore scroll position to ', scroll);
                    window.scrollTo(scroll.x || 0, scroll.y || 0);
                }
                break;
        }
    }
};

module.exports = RouterMixin;
<|endoftext|>


<commit_before>(function (exports) {

	exports.VisualTimer	= VisualTimer;

	JSUS = node.JSUS;

	VisualTimer.id = 'visualtimer';
	VisualTimer.name = 'Visual Timer';
	VisualTimer.version = '0.3.3';
	VisualTimer.description = 'Display a timer for the game. Timer can trigger events. Only for countdown smaller than 1h.';

	VisualTimer.dependencies = {
		GameTimer : {},
		JSUS: {}
	};

	function VisualTimer (options) {
		this.options = options;
		this.id = options.id;

		this.gameTimer = null;

		this.timerDiv = null;	// the DIV in which to display the timer
		this.root = null;		// the parent element
		this.fieldset = {
						legend: 'Time left',
						id: this.id + '_fieldset'
		};

		this.init(this.options);
	}

	VisualTimer.prototype.init = function (options) {
		options = options || this.options;
		var that = this;
		(function initHooks() {
			if (options.hooks) {
				if (!options.hooks instanceof Array) {
					options.hooks = [options.hooks];
				}
			}
			else {
				options.hooks = [];
			}

			options.hooks.push({hook: that.updateDisplay,
								ctx: that
			});
		})();

		this.gameTimer = (options.gameTimer) || new node.GameTimer();

		if (this.gameTimer) {
			this.gameTimer.init(options);
		}
		else {
			node.log('GameTimer object could not be initialized. VisualTimer will not work properly.', 'ERR');
		}

	};

	VisualTimer.prototype.getRoot = function () {
		return this.root;
	};

	VisualTimer.prototype.append = function (root) {
		this.root = root;
		this.timerDiv = node.window.addDiv(root, this.id + '_div');
		this.updateDisplay();
		return root;
	};

	VisualTimer.prototype.updateDisplay = function () {
		if (!this.gameTimer.milliseconds || this.gameTimer.milliseconds === 0) {
			this.timerDiv.innerHTML = '00:00';
			return;
		}
		var time = this.gameTimer.milliseconds - this.gameTimer.timePassed;
		time = JSUS.parseMilliseconds(time);
		var minutes = (time[2] < 10) ? '' + '0' + time[2] : time[2];
		var seconds = (time[3] < 10) ? '' + '0' + time[3] : time[3];
		this.timerDiv.innerHTML = minutes + ':' + seconds;
	};

	VisualTimer.prototype.start = function() {
		this.updateDisplay();
		this.gameTimer.start();
	};

	VisualTimer.prototype.restart = function (options) {
		this.init(options);
		this.start();
	};

	VisualTimer.prototype.stop = function (options) {
		this.gameTimer.stop();
	};

	VisualTimer.prototype.resume = function (options) {
		this.gameTimer.resume();
	};

	VisualTimer.prototype.listeners = function () {
		var that = this;
		node.on('LOADED', function() {
			var timer = node.game.gameLoop.getAllParams(node.game.gameState).timer;
			if (timer) {
				timer = JSUS.clone(timer);
				that.timerDiv.className = '';
				var options = {},
					typeoftimer = typeof timer;
				switch (typeoftimer) {

					case 'number':
						options.milliseconds = timer;
						break;
					case 'object':
						options = timer;
						break;
					case 'function':
						options.milliseconds = timer
						break;
					case 'string':
						options.milliseconds = Number(timer);
						break;
				};

				if (!options.milliseconds) return;

				if ('function' === typeof options.milliseconds) {
					options.milliseconds = options.milliseconds.call(node.game);
				}

				if (!options.timeup) {
					options.timeup = 'DONE';
				}

				that.gameTimer.init(options);
				that.start();
			}
		});

		node.on('DONE', function() {
			// TODO: This should be enabled again
			that.gameTimer.stop();
			that.timerDiv.className = 'strike';
		});
	};

})(node.window.widgets);<commit_msg>classname settings for VisualTimer<commit_after>(function (exports) {

	exports.VisualTimer	= VisualTimer;

	JSUS = node.JSUS;

	VisualTimer.id = 'visualtimer';
	VisualTimer.name = 'Visual Timer';
	VisualTimer.version = '0.3.3';
	VisualTimer.description = 'Display a timer for the game. Timer can trigger events. Only for countdown smaller than 1h.';

	VisualTimer.dependencies = {
		GameTimer : {},
		JSUS: {}
	};

	function VisualTimer (options) {
		this.options = options;
		this.id = options.id;

		this.gameTimer = null;

		this.timerDiv = null;	// the DIV in which to display the timer
		this.root = null;		// the parent element
		this.fieldset = {
						legend: 'Time left',
						id: this.id + '_fieldset'
		};

		this.init(this.options);
	}

	VisualTimer.prototype.init = function (options) {
		options = options || this.options;
		var that = this;
		(function initHooks() {
			if (options.hooks) {
				if (!options.hooks instanceof Array) {
					options.hooks = [options.hooks];
				}
			}
			else {
				options.hooks = [];
			}

			options.hooks.push({hook: that.updateDisplay,
								ctx: that
			});
		})();

		this.gameTimer = (options.gameTimer) || new node.GameTimer();

		if (this.gameTimer) {
			this.gameTimer.init(options);
		}
		else {
			node.log('GameTimer object could not be initialized. VisualTimer will not work properly.', 'ERR');
		}

		if (this.timerDiv) {
			this.timerDiv.className = options.className || '';
		}

	};

	VisualTimer.prototype.getRoot = function () {
		return this.root;
	};

	VisualTimer.prototype.append = function (root) {
		this.root = root;
		this.timerDiv = node.window.addDiv(root, this.id + '_div');
		this.updateDisplay();
		return root;
	};

	VisualTimer.prototype.updateDisplay = function () {
		if (!this.gameTimer.milliseconds || this.gameTimer.milliseconds === 0) {
			this.timerDiv.innerHTML = '00:00';
			return;
		}
		var time = this.gameTimer.milliseconds - this.gameTimer.timePassed;
		time = JSUS.parseMilliseconds(time);
		var minutes = (time[2] < 10) ? '' + '0' + time[2] : time[2];
		var seconds = (time[3] < 10) ? '' + '0' + time[3] : time[3];
		this.timerDiv.innerHTML = minutes + ':' + seconds;
	};

	VisualTimer.prototype.start = function() {
		this.updateDisplay();
		this.gameTimer.start();
	};

	VisualTimer.prototype.restart = function (options) {
		this.init(options);
		this.start();
	};

	VisualTimer.prototype.stop = function (options) {
		this.gameTimer.stop();
	};

	VisualTimer.prototype.resume = function (options) {
		this.gameTimer.resume();
	};

	VisualTimer.prototype.listeners = function () {
		var that = this;
		node.on('LOADED', function() {
			var timer = node.game.gameLoop.getAllParams(node.game.gameState).timer;
			if (timer) {
				timer = JSUS.clone(timer);
				that.timerDiv.className = '';
				var options = {},
					typeoftimer = typeof timer;
				switch (typeoftimer) {

					case 'number':
						options.milliseconds = timer;
						break;
					case 'object':
						options = timer;
						break;
					case 'function':
						options.milliseconds = timer
						break;
					case 'string':
						options.milliseconds = Number(timer);
						break;
				};

				if (!options.milliseconds) return;

				if ('function' === typeof options.milliseconds) {
					options.milliseconds = options.milliseconds.call(node.game);
				}

				if (!options.timeup) {
					options.timeup = 'DONE';
				}

				that.gameTimer.init(options);
				that.start();
			}
		});

		node.on('DONE', function() {
			// TODO: This should be enabled again
			that.gameTimer.stop();
			that.timerDiv.className = 'strike';
		});
	};

})(node.window.widgets);<|endoftext|>


<commit_before>import Vue from 'vue';
import Router from 'vue-router';
import index from '../views/index';
import list from '../views/list';
import topic from '../views/topic';
import login from '../views/login';
import newTopic from '../views/new';
import user from '../views/user';
import message from '../views/message';

Vue.use(Router);

export default new Router({
    mode: 'history',
    routes: [{
        path: '/',
        component: index,
        meta: {
            appTitle: '首页'
        }
    },
    {
        path: '/list',
        name: 'list',
        component: list,
        meta: {
            appTitle: {
                all: '全部',
                good: '精华',
                ask: '问答',
                job: '招聘'
            }
        }
    },
    {
        path: '/topic/:id',
        name: 'topic',
        component: topic,
        meta: {
            appTitle: '主题'
        }
    },
    {
        path: '/user/:userName',
        name: 'user',
        component: user,
        meta: {
            appTitle: '用户信息'
        }
    },
    {
        path: '/message',
        name: 'message',
        component: message,
        meta: {
            appTitle: '消息',
            requiresAuth: true
        }
    },
    {
        path: '/login',
        name: 'login',
        component: login,
        meta: {
            appTitle: '登录'
        }
    },
    {
        path: '/newTopic',
        name: 'newTopic',
        component: newTopic,
        meta: {
            appTitle: '新增主题',
            requiresAuth: true
        }
    }]
});
<commit_msg>opt_解决github page首页不触发路由的问题 (#31)<commit_after>import Vue from 'vue';
import Router from 'vue-router';
import index from '../views/index';
import list from '../views/list';
import topic from '../views/topic';
import login from '../views/login';
import newTopic from '../views/new';
import user from '../views/user';
import message from '../views/message';

Vue.use(Router);

export default new Router({
    mode: 'history',
    routes: [{
        path: './',
        component: index,
        meta: {
            appTitle: '首页'
        }
    },
    {
        path: './list',
        name: 'list',
        component: list,
        meta: {
            appTitle: {
                all: '全部',
                good: '精华',
                ask: '问答',
                job: '招聘'
            }
        }
    },
    {
        path: './topic/:id',
        name: 'topic',
        component: topic,
        meta: {
            appTitle: '主题'
        }
    },
    {
        path: './user/:userName',
        name: 'user',
        component: user,
        meta: {
            appTitle: '用户信息'
        }
    },
    {
        path: './message',
        name: 'message',
        component: message,
        meta: {
            appTitle: '消息',
            requiresAuth: true
        }
    },
    {
        path: './login',
        name: 'login',
        component: login,
        meta: {
            appTitle: '登录'
        }
    },
    {
        path: './newTopic',
        name: 'newTopic',
        component: newTopic,
        meta: {
            appTitle: '新增主题',
            requiresAuth: true
        }
    }]
});
<|endoftext|>


<commit_before><commit_msg>Working with promises and queries<commit_after>/**
 Latest edit: Troy Herbison on March 28
 */

const url_db = 'mongodb://localhost:27017/folding';
const url_team = 'http://fah-web.stanford.edu/daily_team_summary.txt';
const http = require('http');
var Vue = require('vue');
var VueResource = require('vue-resource');

Vue.use(VueResource);
/*const app = require('express')()

const vjmServer = require('vue-jwt-mongo').Server({
  mongoUrl: url_db,
  jwtSecret: 'shhh'
})

app.post('/auth/register', vjmServer.registerHandler)
app.post('/auth/login', vjmServer.loginHandler)
app.post('/auth/refresh', vjmServer.refreshHandler)
app.get('/protected', vjmServer.jwtProtector, (request, response) => {
    console.log(request.user.username)
    })
*/

//{
	//http.get(url_team, function(res) {
  // GET /someUrl
 /* VueResource.http.get(url_db, function(res) {
  	console.log("pinged db");
  */

  /*new Vue({
  	data: {
		_id : { name : 'string', teamID : 'string' },
		rank : int,
		score : int,
		units : int,
		rankChange : int,
		scoreChange : int,
		unitsChange : int,
		date : Date,
		hourly : [
			{
				rank : int,
				score : int,
				units : int,
				date : Date
			}
		],
		daily : [
			{
				rank : int,
				score : int,
				units : int,
				rankChange : int,
				scoreChange : int,
				unitsChange : int,
				date : Date
			}
		]
    },

    ready: function() {

        // GET request
        this.$http.get(url_db, function (data) {
            // set data on vm
            //this.$set('origin', data)

        }).error(function (data, status, request) {
            // handle error
        })

      }
})*/

/*process.on('unhandledRejection', (err, p) => {
  console.log('An unhandledRejection occurred');
  console.log(`Rejected Promise: ${p}`);
  console.log(`Rejection: ${err}`);
});*/

/*Vue.http.get(url_db, function(res){
	if (res.statusCode !== 200) {
		console.log('HTTP request for team data failed');
		return;
	}
/*
  //To print the parameters
  console.log(req.query.hdmi);
  console.log(req.query.resolution);

  //Remember to sanitize the query before passing it to db
  var query = {};
  if (req.query.resolution) query.resolution = req.query.resolution;
  if (req.query.resolution) query.hdmi = req.query.hdmi;

  db.displays.find(query, function(err, displays){
    if (err) {
      res.send(err);
    }
    else {
      return res.json(displays);
    }
  });*/

/*Vue.http.get(url_db, function(res, req){

	if(!res)
	{
		return;
	}

	if(!req)
	{
		return;
	}
});*/

 /*function yourExportedFunction() {
 	console.log("in func");
     var p = Vue.http.get(url_db).then(response => {

    // get body data
    this.someData = response.body;

  }, response => {
    // error callback
  });
     p.catch(() => {}); // add an empty catch handler
     return p;
 }

 yourExportedFunction();*/

//*********left off here and below
//working promise code if the url is http for example(url_team)
/*var somevar = false;
var PTest = function () {
    return Vue.http.get(url_team, function(resolve, reject) {
    if (somevar === true)
        resolve();
    else
        reject();
	});
}
var myfunc = PTest();
myfunc.then(function () {
     console.log("Promise Resolved");
}).catch(function () {
     console.log("Promise Rejected");
});*/

var MongoClient = require('mongodb').MongoClient
  , assert = require('assert');

// Use connect method to connect to the Server
MongoClient.connect(url_db, function(err, db) {
  assert.equal(null, err);
  console.log("Connected correctly to server");

  //var obj = db.collection('users').find({_id : {name: 'FNP', teamID : '118560'}});

  var obj = db.collection('users').find().limit(100).sort({ "score" : -1 });

  console.log(obj);

  db.close();
});<|endoftext|>


<commit_before>import Vue from 'vue'
import Router from 'vue-router'
import dashboard from '../pages/dashboard/index.vue'
import dashboard2 from '../pages/dashboard2/index.vue'
Vue.use (Router)

export default new Router ({
  routes: [
    {
      name: 'Dashboard',
      path: '/',
      component: dashboard
    },
    {
      path: '*',
      redirect: '/'
    },
    {
      name: 'dashboard2',
      path: '/',
      component: dashboard2
    }
  ]
})
<commit_msg>new routes<commit_after>import Vue from 'vue'
import Router from 'vue-router'
import dashboard from '../pages/dashboard/index.vue'
import dashboard2 from '../pages/dashboard2/index.vue'
Vue.use(Router)

const routes = [
  {
    name: 'Dashboard',
    path: '/',
    component: dashboard
  },
  {
    path: '*',
    redirect: '/home'
  },
  {
    name: 'home',
    path: '/home',
    component: dashboard2
  }
]

export default new Router({
  routes: routes
})
<|endoftext|>


<commit_before>var DEFAULTFILESPATH = __dirname + '/public/files/'
var DEFAULTDOWNLOADPATH = __dirname + '/public/downloads/'
var DEFAULTTORRENTPATH = __dirname + '/torrents.txt'
var DEFAULTLOGPATH = __dirname + '/log.txt'

// file management
var fs = require('fs')
fs.writeFile(DEFAULTLOGPATH, '', 'utf-8', function (err) {
  if (err) log(err)
})

var cp = require('child_process')

// Setup basic express server
var auth = require('http-auth')

var basic = auth.basic({
  realm: 'Protected area. Please disperse !',
  file: __dirname + '/.htpasswd'
})

// setup http server
var express = require('express')
var app = express()
var compression = require('compression')
app.use(compression())
var http = require('http')
http.globalAgent.maxSockets = Infinity
var server = http.createServer(basic, app)

var port = process.env.PORT || 80

server.listen(port, function () {
  log('Server listening at port ' + port)
})
// Routing
app.use(express.static(__dirname + '/public'))

// socket io
var io = require('socket.io')(server)

// webtorrent
var WebTorrent = require('webtorrent')

// Torrent memory tab
var TorrentUrlToChild = {}
var TorrentHashToChild = {}
var TorrentWaitList = []

// Auto start torrent in file
fs.writeFile(DEFAULTTORRENTPATH, '', 'utf-8', function (err) {
  if (err) throw err
})
setInterval(startPointTorrent, 30000)

app.get('/files/', function (req, res) {
  var filename = DEFAULTFILESPATH + req.query.f
  fs.stat(filename, function (err, stats) {
    if (stats) {
      res.setHeader('Content-disposition', 'attachment; filename=' + req.query.f)
      res.setHeader('Content-Length', stats.size)
      res.setHeader('Content-type', 'application/octet-stream')
      var fReadStream = fs.createReadStream(filename, {highWaterMark: Math.pow(2, 16)})
      fReadStream.pipe(res)
    } else {
      res.end("Le fichier n'existe pas")
    }
  })
})

io.on('connection', function (socket) {
  socket.on('ready', function () {
    for (var key in TorrentHashToChild) {
      TorrentHashToChild[key].send({'type': 'info'})
    }

    socket.on('download-t', function (url) {
      startTorrent(url)
    })
  })

  socket.on('list-d', function (dir) {
    fs.readdir(DEFAULTFILESPATH + dir, function (err, files) {
      if (err) return log(err)
      var list = {}
      var totalSize = 0
      if (files.length > 0) {
        files.forEach(function (file) {
          var stats = fs.statSync(DEFAULTFILESPATH + dir + file)
          if (stats.isFile()) {
            list[file] = stats
          } else {
            stats.size = sizeRecursif(DEFAULTFILESPATH + dir + file)
            list[file] = stats
          }
          list[file].isfile = stats.isFile()
          list[file].isdir = stats.isDirectory()

          totalSize += stats.size

          if (Object.keys(list).length === files.length) {
            socket.emit('list-d', {'totalSize': totalSize,'files': list})
          }
        })
      } else {
        socket.emit('list-d', {})
      }
    })
  })

  socket.on('remove-t', function (hash) {
    log('Remove torrent: ' + hash)
    TorrentHashToChild[hash].send({'type': 'remove'})
    socket.emit('finish-t', hash)
  })

  socket.on('remove-d', function (file) {
    log('Remove file: ' + file)
    fs.stat(DEFAULTFILESPATH + file, function (err, stats) {
      if (err) return log(err)
      if (stats.isDirectory()) {
        removeRecursif(DEFAULTFILESPATH + file)
        socket.emit('update-d')
      } else {
        fs.unlink(DEFAULTFILESPATH + file, function (err) {
          if (err) return log(err)
          socket.emit('update-d')
        })
      }
    })
  })

  socket.on('rename-d', function (data) {
    log('Rename: ' + data.oldname + ' In: ' + data.newname)
    fs.rename(DEFAULTFILESPATH + data.path + '/' + data.oldname, DEFAULTFILESPATH + data.path + '/' + data.newname, function (err) {
      if (err) return log(err)
      socket.emit('update-d')
    })
  })

  socket.on('mkdir', function (data) {
    log('Mkdir: ' + data.path + '/' + data.name)
    fs.mkdir(DEFAULTFILESPATH + data.path + '/' + data.name, function () {
      socket.emit('update-d')
    })
  })

  socket.on('mv', function (data) {
    fs.rename(DEFAULTFILESPATH + data.path + data.file, DEFAULTFILESPATH + data.path + data.folder + '/' + data.file, function (err) {
      if (err) return log(err)
      socket.emit('update-d')
    })
  })
})

function getDate () {
  var date = new Date()
  return date.getDate() + '/' + (date.getMonth() + 1) + ' ' + (date.getHours() + 1) + ':' + (date.getMinutes() + 1) + ':' + (date.getSeconds() + 1)
}

function log (text) {
  console.log(text)
  fs.appendFile(DEFAULTLOGPATH, '[' + getDate() + '] ' + text + '\n', 'utf8', function (err) {
    if (err) throw err
  })
}

function startTorrent (url) {
  log('Trying to download: ' + url)

  // evite de lancer deux fois le meme torrent
  if (TorrentUrlToChild[url] == null) {
    // Si trop de torrent en cours
    if (Object.keys(TorrentUrlToChild).length < 3) {
      var n = cp.fork(__dirname + '/tclient.js')
      TorrentUrlToChild[url] = n
      io.sockets.emit('start-t')
      n.on('message', function (data) {
        switch (data.type) {
          case 'finish':
            io.sockets.emit('finish-t', data.hash)
            n.kill('SIGHUP')
            delete TorrentUrlToChild[url]
            delete TorrentHashToChild[data.hash]
            fs.renameSync(DEFAULTDOWNLOADPATH + data.name, DEFAULTFILESPATH + data.name)
            // Relance un torrent si il y en a en attente
            if (TorrentWaitList.length > 0) {
              var newUrl = TorrentWaitList[0]
              startTorrent(newUrl)
              TorrentWaitList.shift()
            }
            break
          case 'info':
            io.sockets.emit('list-t', data.torrent)
            TorrentHashToChild[data.torrent.hash] = n
            break
          case 'remove':
            io.sockets.emit('finish-t', data.hash)
            n.kill('SIGHUP')
            delete TorrentUrlToChild[url]
            delete TorrentHashToChild[data.hash]
            fs.unlinkSync(DEFAULTDOWNLOADPATH + data.name)
            // Relance un torrent si il y en a en attente
            if (TorrentWaitList.length > 0) {
              startTorrent(TorrentWaitList[0])
              TorrentWaitList.shift()
            }
        }
      })

      n.send({'type': 'download', 'torrent': url})

    } else {
      log('Too much client. Adding torrent to the waitlist.')
      // On push dans la liste d'attente
      if (TorrentWaitList.indexOf(url) === -1)
        TorrentWaitList.push(url)
    }
  } else {
    log('Torrent is already downloading.')
  }
}

function removeRecursif (path) {
  if (fs.existsSync(path)) {
    fs.readdirSync(path).forEach(function (file, index) {
      var curPath = path + '/' + file
      if (fs.lstatSync(curPath).isDirectory()) { // recurse
        removeRecursif(curPath)
      } else { // delete file
        fs.unlinkSync(curPath)
      }
    })
    fs.rmdirSync(path)
  }
}

function sizeRecursif (path) {
  var size = 0
  if (fs.existsSync(path)) {
    fs.readdirSync(path).forEach(function (file, index) {
      var curPath = path + '/' + file
      if (fs.lstatSync(curPath).isDirectory()) { // recurse
        sizeRecursif(curPath)
      } else { // read size
        size += fs.statSync(curPath).size
      }
    })
    return size
  }
}

function startPointTorrent () {
  log('Scan for new torrent.')
  fs.readFile(DEFAULTTORRENTPATH, 'utf-8', function (err, data) {
    if (err) return log(err)
    var torrents = data.split('\n')
    fs.writeFile(DEFAULTTORRENTPATH, '', 'utf-8', function (err) {
      if (err) return log(err)
      torrents.forEach(function (element) {
        if (element !== '') {
          startTorrent(element)
        }
      })
    })
  })
}
<commit_msg>default start<commit_after>var DEFAULTFILESPATH = __dirname + '/public/files/'
var DEFAULTDOWNLOADPATH = __dirname + '/public/downloads/'
var DEFAULTTORRENTPATH = __dirname + '/torrents.txt'
var DEFAULTLOGPATH = __dirname + '/log.txt'

// file management
var fs = require('fs')
fs.writeFile(DEFAULTLOGPATH, '', 'utf-8', function (err) {
  if (err) log(err)
})
fs.mkdir(DEFAULTFILESPATH)
fs.mkdir(DEFAULTDOWNLOADPATH)

var cp = require('child_process')

// Setup basic express server
var auth = require('http-auth')

var basic = auth.basic({
  realm: 'Protected area. Please disperse !',
  file: __dirname + '/.htpasswd'
})

// setup http server
var express = require('express')
var app = express()
var compression = require('compression')
app.use(compression())
var http = require('http')
http.globalAgent.maxSockets = Infinity
var server = http.createServer(basic, app)

var port = process.env.PORT || 80

server.listen(port, function () {
  log('Server listening at port ' + port)
})
// Routing
app.use(express.static(__dirname + '/public'))

// socket io
var io = require('socket.io')(server)

// webtorrent
var WebTorrent = require('webtorrent')

// Torrent memory tab
var TorrentUrlToChild = {}
var TorrentHashToChild = {}
var TorrentWaitList = []

// Auto start torrent in file
fs.writeFile(DEFAULTTORRENTPATH, '', 'utf-8', function (err) {
  if (err) throw err
})
setInterval(startPointTorrent, 30000)

app.get('/files/', function (req, res) {
  var filename = DEFAULTFILESPATH + req.query.f
  fs.stat(filename, function (err, stats) {
    if (stats) {
      res.setHeader('Content-disposition', 'attachment; filename=' + req.query.f)
      res.setHeader('Content-Length', stats.size)
      res.setHeader('Content-type', 'application/octet-stream')
      var fReadStream = fs.createReadStream(filename, {highWaterMark: Math.pow(2, 16)})
      fReadStream.pipe(res)
    } else {
      res.end("Le fichier n'existe pas")
    }
  })
})

io.on('connection', function (socket) {
  socket.on('ready', function () {
    for (var key in TorrentHashToChild) {
      TorrentHashToChild[key].send({'type': 'info'})
    }

    socket.on('download-t', function (url) {
      startTorrent(url)
    })
  })

  socket.on('list-d', function (dir) {
    fs.readdir(DEFAULTFILESPATH + dir, function (err, files) {
      if (err) return log(err)
      var list = {}
      var totalSize = 0
      if (files.length > 0) {
        files.forEach(function (file) {
          var stats = fs.statSync(DEFAULTFILESPATH + dir + file)
          if (stats.isFile()) {
            list[file] = stats
          } else {
            stats.size = sizeRecursif(DEFAULTFILESPATH + dir + file)
            list[file] = stats
          }
          list[file].isfile = stats.isFile()
          list[file].isdir = stats.isDirectory()

          totalSize += stats.size

          if (Object.keys(list).length === files.length) {
            socket.emit('list-d', {'totalSize': totalSize,'files': list})
          }
        })
      } else {
        socket.emit('list-d', {})
      }
    })
  })

  socket.on('remove-t', function (hash) {
    log('Remove torrent: ' + hash)
    TorrentHashToChild[hash].send({'type': 'remove'})
    socket.emit('finish-t', hash)
  })

  socket.on('remove-d', function (file) {
    log('Remove file: ' + file)
    fs.stat(DEFAULTFILESPATH + file, function (err, stats) {
      if (err) return log(err)
      if (stats.isDirectory()) {
        removeRecursif(DEFAULTFILESPATH + file)
        socket.emit('update-d')
      } else {
        fs.unlink(DEFAULTFILESPATH + file, function (err) {
          if (err) return log(err)
          socket.emit('update-d')
        })
      }
    })
  })

  socket.on('rename-d', function (data) {
    log('Rename: ' + data.oldname + ' In: ' + data.newname)
    fs.rename(DEFAULTFILESPATH + data.path + '/' + data.oldname, DEFAULTFILESPATH + data.path + '/' + data.newname, function (err) {
      if (err) return log(err)
      socket.emit('update-d')
    })
  })

  socket.on('mkdir', function (data) {
    log('Mkdir: ' + data.path + '/' + data.name)
    fs.mkdir(DEFAULTFILESPATH + data.path + '/' + data.name, function () {
      socket.emit('update-d')
    })
  })

  socket.on('mv', function (data) {
    fs.rename(DEFAULTFILESPATH + data.path + data.file, DEFAULTFILESPATH + data.path + data.folder + '/' + data.file, function (err) {
      if (err) return log(err)
      socket.emit('update-d')
    })
  })
})

function getDate () {
  var date = new Date()
  return date.getDate() + '/' + (date.getMonth() + 1) + ' ' + (date.getHours() + 1) + ':' + (date.getMinutes() + 1) + ':' + (date.getSeconds() + 1)
}

function log (text) {
  console.log(text)
  fs.appendFile(DEFAULTLOGPATH, '[' + getDate() + '] ' + text + '\n', 'utf8', function (err) {
    if (err) throw err
  })
}

function startTorrent (url) {
  log('Trying to download: ' + url)

  // evite de lancer deux fois le meme torrent
  if (TorrentUrlToChild[url] == null) {
    // Si trop de torrent en cours
    if (Object.keys(TorrentUrlToChild).length < 3) {
      var n = cp.fork(__dirname + '/tclient.js')
      TorrentUrlToChild[url] = n
      io.sockets.emit('start-t')
      n.on('message', function (data) {
        switch (data.type) {
          case 'finish':
            io.sockets.emit('finish-t', data.hash)
            n.kill('SIGHUP')
            delete TorrentUrlToChild[url]
            delete TorrentHashToChild[data.hash]
            fs.renameSync(DEFAULTDOWNLOADPATH + data.name, DEFAULTFILESPATH + data.name)
            // Relance un torrent si il y en a en attente
            if (TorrentWaitList.length > 0) {
              var newUrl = TorrentWaitList[0]
              startTorrent(newUrl)
              TorrentWaitList.shift()
            }
            break
          case 'info':
            io.sockets.emit('list-t', data.torrent)
            TorrentHashToChild[data.torrent.hash] = n
            break
          case 'remove':
            io.sockets.emit('finish-t', data.hash)
            n.kill('SIGHUP')
            delete TorrentUrlToChild[url]
            delete TorrentHashToChild[data.hash]
            fs.unlinkSync(DEFAULTDOWNLOADPATH + data.name)
            // Relance un torrent si il y en a en attente
            if (TorrentWaitList.length > 0) {
              startTorrent(TorrentWaitList[0])
              TorrentWaitList.shift()
            }
        }
      })

      n.send({'type': 'download', 'torrent': url})

    } else {
      log('Too much client. Adding torrent to the waitlist.')
      // On push dans la liste d'attente
      if (TorrentWaitList.indexOf(url) === -1)
        TorrentWaitList.push(url)
    }
  } else {
    log('Torrent is already downloading.')
  }
}

function removeRecursif (path) {
  if (fs.existsSync(path)) {
    fs.readdirSync(path).forEach(function (file, index) {
      var curPath = path + '/' + file
      if (fs.lstatSync(curPath).isDirectory()) { // recurse
        removeRecursif(curPath)
      } else { // delete file
        fs.unlinkSync(curPath)
      }
    })
    fs.rmdirSync(path)
  }
}

function sizeRecursif (path) {
  var size = 0
  if (fs.existsSync(path)) {
    fs.readdirSync(path).forEach(function (file, index) {
      var curPath = path + '/' + file
      if (fs.lstatSync(curPath).isDirectory()) { // recurse
        sizeRecursif(curPath)
      } else { // read size
        size += fs.statSync(curPath).size
      }
    })
    return size
  }
}

function startPointTorrent () {
  log('Scan for new torrent.')
  fs.readFile(DEFAULTTORRENTPATH, 'utf-8', function (err, data) {
    if (err) return log(err)
    var torrents = data.split('\n')
    fs.writeFile(DEFAULTTORRENTPATH, '', 'utf-8', function (err) {
      if (err) return log(err)
      torrents.forEach(function (element) {
        if (element !== '') {
          startTorrent(element)
        }
      })
    })
  })
}
<|endoftext|>


<commit_before>// Contact Form Scripts

$(function() {

    $("#contactForm input,#contactForm textarea").jqBootstrapValidation({
        preventSubmit: true,
        submitError: function($form, event, errors) {
            // additional error messages or events
        },
        submitSuccess: function($form, event) {
            event.preventDefault(); // prevent default submit behaviour
            // get values from FORM
            var name = $("input#name").val();
            var email = $("input#email").val();
            var phone = $("input#phone").val();
            var position = $("input#position").val();
            var age = $('input#age').val();
            var message = $("textarea#message").val();
            var firstName = name; // For Success/Failure Message
            // Check for white space in name for Success/Fail message
            if (firstName.indexOf(' ') >= 0) {
                firstName = name.split(' ').slice(0, -1).join(' ');
            }
            $.ajax({
                url: "././mail/contact_me.php",
                type: "POST",
                data: {
                    name: name,
                    phone: phone,
                    email: email,
                    message: message
                },
                cache: false,
                success: function() {
                    // Success message
                    $('#success').html("
");
                    $('#success > .alert-success').html("<button type='button' class='close' data-dismiss='alert' aria-hidden='true'>×")
                        .append("</button>");
                    $('#success > .alert-success')
                        .append("Your message has been sent. ");
                    $('#success > .alert-success')
                        .append('
');

                    //clear all fields
                    $('#contactForm').trigger("reset");
                },
                error: function() {
                    // Fail message
                    $('#success').html("
");
                    $('#success > .alert-danger').html("<button type='button' class='close' data-dismiss='alert' aria-hidden='true'>×")
                        .append("</button>");
                    $('#success > .alert-danger').append($("").text("Sorry " + firstName + ", it seems that my mail server is not responding. Please try again later!"));
                    $('#success > .alert-danger').append('
');
                    //clear all fields
                    $('#contactForm').trigger("reset");
                },
            });
        },
        filter: function() {
            return $(this).is(":visible");
        },
    });

    $("a[data-toggle=\"tab\"]").click(function(e) {
        e.preventDefault();
        $(this).tab("show");
    });
});

/*When clicking on Full hide fail/success boxes */
$('#name').focus(function() {
    $('#success').html('');
});
<commit_msg>testing<commit_after>// Contact Form Scripts

$(function() {

    $("#contactForm input,#contactForm textarea").jqBootstrapValidation({
        preventSubmit: true,
        submitError: function($form, event, errors) {
            // additional error messages or events
        },
        submitSuccess: function($form, event) {
            event.preventDefault(); // prevent default submit behaviour
            // get values from FORM
            var name = $("input#name").val();
            var email = $("input#email").val();
            var phone = $("input#phone").val();
            var position = $("input#position").val();
            var age = $('input#age').val();
            var message = $("textarea#message").val();
            var firstName = name; // For Success/Failure Message
            // Check for white space in name for Success/Fail message
            if (firstName.indexOf(' ') >= 0) {
                firstName = name.split(' ').slice(0, -1).join(' ');
            }
            $.ajax({
                url: "./mail/contact_me.php",
                type: "POST",
                data: {
                    name: name,
                    phone: phone,
                    email: email,
                    position: position,
                    age: age,
                    message: message
                },
                cache: false,
                success: function() {
                    // Success message
                    $('#success').html("
");
                    $('#success > .alert-success').html("<button type='button' class='close' data-dismiss='alert' aria-hidden='true'>×")
                        .append("</button>");
                    $('#success > .alert-success')
                        .append("Your message has been sent. ");
                    $('#success > .alert-success')
                        .append('
');

                    //clear all fields
                    $('#contactForm').trigger("reset");
                },
                error: function() {
                    // Fail message
                    $('#success').html("
");
                    $('#success > .alert-danger').html("<button type='button' class='close' data-dismiss='alert' aria-hidden='true'>×")
                        .append("</button>");
                    $('#success > .alert-danger').append($("").text("Sorry " + firstName + ", it seems that my mail server is not responding. Please try again later!"));
                    $('#success > .alert-danger').append('
');
                    //clear all fields
                    $('#contactForm').trigger("reset");
                },
            });
        },
        filter: function() {
            return $(this).is(":visible");
        },
    });

    $("a[data-toggle=\"tab\"]").click(function(e) {
        e.preventDefault();
        $(this).tab("show");
    });
});

/*When clicking on Full hide fail/success boxes */
$('#name').focus(function() {
    $('#success').html('');
});
<|endoftext|>


<commit_before>/**
 * @file restify-based node.js-server for rswiki
 * @copyright 2013 Berne University of Applied Sciences (BUAS) -- {@link http://bfh.ch}
 * @author Pascal Mainini <pascal.mainini@bfh.ch>
 * @version 0.1.1
 *
 * ! WARNING ! WARNING ! WARNING ! WARNING ! WARNING ! WARNING !
 *
 * THIS FILE HAS NO DEFINITIVE LICENSING INFORMATION.
 * LICENSE IS SUBJECT OF CHANGE ANYTIME SOON - DO NOT DISTRIBUTE!
 *
 * ! WARNING ! WARNING ! WARNING ! WARNING ! WARNING ! WARNING !
 *
 * This is a node.js-server for rswiki based on restify.
 * It mainly implements a REST-API for CRUD-operations on a wiki-page by using the appropriate REST-verbs.
 *
 * The REST-verbs are implemented in the functions api_getPage(), api_savePage(), api_deletePage(),
 * each of these methods works with a page-"object" taking the following form:
 *
 * page {
 *  name:             {String} name of the page <-> filename without .md
 *  content:          {String} markdown-content of the page-file
 *  changeMessage:    {String} message describing the change/delete of the page
 * }
 *
 * There is no assumption made about any of the values in the page-object beeing present and the functions
 * handling these try to take care of that or at least fail gracefully.
 *
 * Internal "communication" is done entirely by passing these objects between callbacks or returning Errors
 * in case they happen.
 *
 * The REST-API currently supports three content-types: text/plain, text/html and application/json.
 * If application/json is requested, the JSON from the api_*-functions is returned "as-is".
 * Otherwise, content-formatting is done by one of the fmt_*-functions according to the requested content-type.
 */

/*jshint node:true, bitwise:true, curly:true, immed:true, indent:2, latedef:true, newcap:true, noarg: true, noempty:true, nonew:true, quotmark:single, undef:true, unused: true, trailing:true, white:false */
/*global DOCUMENT:true, HTML:true, HEAD:true, BODY:true, META:true, TITLE:true, LINK:true, SCRIPT:true, A:true, DIV:true SPAN:true */

/***********************************************************
 * Initialisation
 **********************************************************/

'use strict';

// @todo: make options configurable
var AUDITLOG = true;
var LISTENPORT = 8080;
var WIKIDATA = '/tmp/wikidata';
var PAGEPREFIX = '/page';

var CLIENTRESOURCES = {domo: '/node_modules/domo/lib/domo.js',
                        md_converter: '/node_modules/pagedown/Markdown.Converter.js',
                        md_sanitizer: '/node_modules/pagedown/Markdown.Sanitizer.js',
                        md_editor: '/lib/wmd-editor/Markdown.Editor.js',
                        md_styles: '/lib/wmd-editor/wmd-styles.css',
                        jquery: '/lib/jquery-1.9.0.js',
                        jquery_rest: '/lib/jquery.rest.js',
                        wikifunctions: '/static/wikifunctions.js'};

require('domo').global();

var filesystem = require('fs'),
  pagedown = require('pagedown'),
  restify = require('restify'),
  git = require('gitty'),
  mimeparse = require('mimeparse'),
  bunyan = require('bunyan');

var logger = bunyan.createLogger({    // @issue stuff logged with logger.debug somehow doesn't appear at all...
  name: 'rswiki',
  stream: process.stdout,
  src: true
});

/***********************************************************
 * Function definitions
 **********************************************************/

//////////////////// REST-API

/**
 * Loads the contents of a wikipage (in markdown) from storage.
 *
 * @param   {restify.Request}   req   Request-object given by restify
 * @param   {restify.Response}  res   Response-object given by restify
 * @param   {Function}          next  Next callback in the chain to call
 * @returns {Object}            The return-value of the next callback in the chain or an Error if something failed.
 */
var api_getPage = function api_getPage (req, res, next) {
  var pageName = req.params.name;
  var fileName = WIKIDATA + '/' + pageName + '.md';

  logger.info({fileName: fileName, page: {name: pageName}}, 'api_getPage: %s', pageName);

  filesystem.exists(fileName, function _fsExists (exists) {
    if (exists) {
      filesystem.readFile(fileName, 'utf8', function _readErr (err, file) {
        if (err) {
          logger.error({error: err, fileName: fileName, page: {name: pageName}}, 'Error occured while loading page %s : %s', pageName, err);
          return next(err);
        } else {
          return next({page: {content: file, name: req.params.name}});
        }
      });
    } else {
      logger.info({fileName: fileName, page: {name: pageName}}, 'Page %s does not exist, returning "null"-content.', pageName);
      return next({page: {content: null, name: pageName}});
    }
  });
};

/**
 * Saves the contents (markdown) of a wikipage to the storage and performs a git-commit.
 *
 * @param   {restify.Request}   req   Request-object given by restify
 * @param   {restify.Response}  res   Response-object given by restify
 * @param   {Function}          next  Next callback in the chain to call
 * @returns {Object}            Forwards to api_getPage WITHOUT returning it (api_getPage calls next callback) or an Error if something fails.
 */
var api_savePage = function api_savePage (req, res, next) {
  var pageName = req.params.name;
  var page = req.params.page;
  var fileName = WIKIDATA + '/' + pageName + '.md';

  logger.info({fileName: fileName, page: {name: pageName}}, 'api_savePage: %s', pageName);

  // @todo synchronize the whole thing somehow?
  filesystem.writeFile(fileName, page.content, 'utf8', function _writeErr(err) {
    if (err) {
      logger.error({error: err, fileName: fileName, page: {name: pageName}}, 'Error occured while writing page %s : %s', pageName, err);
      return next(err);
    } else {
      var repo = new git.Repository(WIKIDATA);
      var gitFiles = [pageName + '.md'];

//      git.config('user.name', data.user.name, function _gitConfigNameErr (err) {   // @bug overrides global config
//        if (gitSuccess(err, callback)) {
//          git.config('user.email', data.user.email, function _gitConfigEMail(err) {
//            if (gitSuccess(err, callback)) {
              repo.add(gitFiles, function _gitAddErr (err) {
                if (err) {
                  logger.error({error: err, fileName: fileName, page: {name: pageName}}, 'Error occured while adding to git, trying to unstage: %s', err);
                  repo.unstage(gitFiles, function _gitUnstageErr (err) {
                      if(err) {
                        logger.error({error: err, fileName: fileName, page: {name: pageName}}, 'Error occured while unstaging: %s', err);
                        return next(err);
                      }
                    });
                  return next(err);
                } else {
                  repo.commit(page.changeMessage, function _gitCommitErr (err) {
                    if (err) {
                      logger.error({error: err, fileName: fileName, page: {name: pageName}}, 'Error occured while commiting to git, trying to unstage: %s', err);
                      repo.unstage(gitFiles, function _gitUnstageErr (err) {
                          if (err) {
                            logger.error({error: err, fileName: fileName, page: {name: pageName}}, 'Error occured while unstaging: %s', err);
                            return next(err);
                          }
                        });
                      return next(err);
                    } else {
                      logger.info({fileName: fileName, page: {name: pageName}}, 'Successfully committed page %s.', pageName);
                    }
                  });
                }
              });
//            }
//          });
//        }
//      });
    }
  });

  api_getPage(req, res, next);    // reload page from storage and give it back to caller
};

/**
 * Deletes a page from the storage and from git.
 *
 * @param   {restify.Request}   req   Request-object given by restify
 * @param   {restify.Response}  res   Response-object given by restify
 * @param   {Function}          next  Next callback in the chain to call
 * @returns {Object}            The return-value of the next callback in the chain or an Error if something failed.
 */
var api_deletePage = function api_deletePage (req, res, next) {
  var pageName = req.params.name;
  var page = req.params.page;
  var fileName = WIKIDATA + '/' + pageName + '.md';

  var repo = new git.Repository(WIKIDATA);
  var gitFiles = [pageName + '.md'];

  logger.info({fileName: fileName, page: {name: pageName}}, 'api_deletePage: %s', pageName);

//  git.config('user.name', data.user.name, function _gitConfigNameErr (err) {   // @bug overrides global config
//    if (gitSuccess(err, callback)) {
//      git.config('user.email', data.user.email, function _gitConfigEMailErr (err) {
//        if (gitSuccess(err, callback)) {
          repo.remove(gitFiles, function _gitRemoveErr (err) {
            if (err) {
              logger.error({error: err, fileName: fileName, page: {name: pageName}}, 'Error while removing page %s from git: %s', pageName, err);
              return next(err);
            } else {
              repo.commit(page.changeMessage, function _gitCommitErr (err) {
                if (err) {
                  logger.error({error: err, fileName: fileName, page: {name: pageName}}, 'Error while committing to git: %s', err);
                  return next(err);
                } else {
                  filesystem.unlink(fileName, function _unlinkErr (err) {
                    if (err) {
                      logger.error({error: err, fileName: fileName, page: {name: pageName}}, 'Error while deleting page %s : %s', pageName, err);
                      return next(err);
                    } else {
                      logger.info({fileName: fileName, page: {name: pageName}}, 'Successfully deleted page %s.', pageName);
                      return next({page: {content: null, name: pageName}});
                    }
                  });
                }
              });
            }
          });
//        }
//      });
//    }
//  });
};

//////////////////// output-formatters

/**
 * Formatter called by restify when requestor wants text/html.
 *
 * @param   {restify.Request}   req   Request-object given by restify
 * @param   {restify.Response}  res   Response-object given by restify
 * @param   {Object}            body  The effective wiki-page as returned by the api_*-methods as JSON.
 * @returns {String}            HTML-representation of the page (or the Error)
 */
var fmt_Html = function fmt_Html (req, res, body) {

  if (body instanceof Error) {

    return DOCUMENT(
      HTML({lang: 'en'},
        HEAD(
          META({charset: 'utf-8'}),
          TITLE(body.statusCode ? body.statusCode  + ': ' + body.message : body.message)
        ),
        BODY(
          DIV({id: 'rswiki_error'}, (body.statusCode ? body.statusCode  + ': ' + body.message : body.message))
        )
      )
    ).outerHTML + '\n';

  } else {

    var pageContent;
    if (body.page.content) {
      pageContent = pagedown.getSanitizingConverter().makeHtml(body.page.content);   // or: new pagedown.Converter();
    } else {
      pageContent = '';
    }

    return DOCUMENT(
      HTML({lang: 'en'},
        HEAD(
          META({charset: 'utf-8'}),
          TITLE(body.page.name),
          LINK({rel: 'stylesheet', type: 'text/css', href: CLIENTRESOURCES.md_styles}),
          SCRIPT({src: CLIENTRESOURCES.domo}),
          SCRIPT({src: CLIENTRESOURCES.md_converter}),
          SCRIPT({src: CLIENTRESOURCES.md_sanitizer}),
          SCRIPT({src: CLIENTRESOURCES.md_editor}),
          SCRIPT({src: CLIENTRESOURCES.jquery}),
          SCRIPT({src: CLIENTRESOURCES.jquery_rest}),
          SCRIPT({src: CLIENTRESOURCES.wikifunctions})
        ),
        BODY(
          DIV({id: 'rswiki_header'},
            DIV({id: 'rswiki_title'}, body.page.name),
            DIV({id: 'rswiki_navi'},
              A({id: 'rswiki_button_edit', href: '#'}, 'edit'),
              SPAN({id: 'rswiki_button_delete'}, ' | ', A({href: '#'}, 'delete'))
            )
          ),
          DIV({id: 'rswiki_editor'}),
          DIV({id: 'rswiki_content'}, '%#%PAGECONTENT%#%')
        )
      )
    ).outerHTML.replace('%#%PAGECONTENT%#%', pageContent) + '\n';   // or: new pagedown.Converter();

  }
};

/**
 * Formatter called by restify when requestor wants text/plain.
 *
 * @param   {restify.Request}   req   Request-object given by restify
 * @param   {restify.Response}  res   Response-object given by restify
 * @param   {Object}            body  The effective wiki-page as returned by the api_*-methods as JSON.
 * @returns {String}            Plaintext-representation of the page (or the Error)
 */
var fmt_Text = function fmt_Text (req, res, body) {
  if (body instanceof Error) {
    return 'Error!\n\n' +
      (body.statusCode ? 'Statuscode: ' + body.statusCode + '\n' : '') +
      'Message: ' + body.message + '\n';
  } else {
    return 'Title: ' + body.page.name +
      '\n------------------ START CONTENT --------------------\n' +
      body.page.content +
      '\n------------------- END CONTENT ---------------------\n';
  }
};

/***********************************************************
 * Main application
 **********************************************************/

//////////////////// setup server

var server = restify.createServer({
  formatters: {
    'text/html': fmt_Html,
    'text/plain': fmt_Text
//    'text/x-markdown': fmt_Markdown   @todo implement text/x-markdown
    // application/json gets implicitly handled by restify
  }
});  // @todo SSL...

//// server: events
if (AUDITLOG) {
  server.on('after', restify.auditLogger({log: logger}));
}

// @issue workaround for seemingly improper accept-header-evaluation by restify...
server.pre(function _mimeFix (req, res, next) {
  req.headers.accept = mimeparse.bestMatch(['text/plain','text/html','application/json'], req.headers.accept);
  return next();
});

//// server: general handlers
server.use(restify.requestLogger());    // @issue requestLogger logs NOTHING!
server.use(restify.bodyParser());
server.use(restify.acceptParser(server.acceptable));

//// server: static content
server.get(/\/static\/?.*/, restify.serveStatic({directory: '.'}));   // @issue serveStatic doesn't emit NotFound-event...
server.get(/\/lib\/?.*/, restify.serveStatic({directory: '.'}));
server.get(/\/node_modules\/?.*/, restify.serveStatic({directory: '.'}));

//// server: page API
server.get(PAGEPREFIX + '/:name', api_getPage);   // @todo GET redirect / to a mainpage or provide a list of pages?
server.put(PAGEPREFIX + '/:name', api_savePage);
server.post(PAGEPREFIX + '/:name', api_savePage);
server.del(PAGEPREFIX + '/:name', api_deletePage);

//// start server
server.listen(LISTENPORT, function listenCallback () {
  logger.info({serverName: server.name, serverURL: server.url}, '%s listening at %s.', server.name, server.url);
});
<commit_msg>adjusted paths<commit_after>/**
 * @file restify-based node.js-server for rswiki
 * @copyright 2013 Berne University of Applied Sciences (BUAS) -- {@link http://bfh.ch}
 * @author Pascal Mainini <pascal.mainini@bfh.ch>
 * @version 0.1.1
 *
 * ! WARNING ! WARNING ! WARNING ! WARNING ! WARNING ! WARNING !
 *
 * THIS FILE HAS NO DEFINITIVE LICENSING INFORMATION.
 * LICENSE IS SUBJECT OF CHANGE ANYTIME SOON - DO NOT DISTRIBUTE!
 *
 * ! WARNING ! WARNING ! WARNING ! WARNING ! WARNING ! WARNING !
 *
 * This is a node.js-server for rswiki based on restify.
 * It mainly implements a REST-API for CRUD-operations on a wiki-page by using the appropriate REST-verbs.
 *
 * The REST-verbs are implemented in the functions api_getPage(), api_savePage(), api_deletePage(),
 * each of these methods works with a page-"object" taking the following form:
 *
 * page {
 *  name:             {String} name of the page <-> filename without .md
 *  content:          {String} markdown-content of the page-file
 *  changeMessage:    {String} message describing the change/delete of the page
 * }
 *
 * There is no assumption made about any of the values in the page-object beeing present and the functions
 * handling these try to take care of that or at least fail gracefully.
 *
 * Internal "communication" is done entirely by passing these objects between callbacks or returning Errors
 * in case they happen.
 *
 * The REST-API currently supports three content-types: text/plain, text/html and application/json.
 * If application/json is requested, the JSON from the api_*-functions is returned "as-is".
 * Otherwise, content-formatting is done by one of the fmt_*-functions according to the requested content-type.
 */

/*jshint node:true, bitwise:true, curly:true, immed:true, indent:2, latedef:true, newcap:true, noarg: true, noempty:true, nonew:true, quotmark:single, undef:true, unused: true, trailing:true, white:false */
/*global DOCUMENT:true, HTML:true, HEAD:true, BODY:true, META:true, TITLE:true, LINK:true, SCRIPT:true, A:true, DIV:true SPAN:true */

/***********************************************************
 * Initialisation
 **********************************************************/

'use strict';

// @todo: make options configurable
var AUDITLOG = true;
var LISTENPORT = 8080;
var WIKIDATA = '/tmp/wikidata';
var PAGEPREFIX = '/page';

var CLIENTRESOURCES = {domo: '/node_modules/domo/lib/domo.js',
                        md_converter: '/node_modules/pagedown/Markdown.Converter.js',
                        md_sanitizer: '/node_modules/pagedown/Markdown.Sanitizer.js',
                        md_editor: '/lib/wmd-editor/Markdown.Editor.js',
                        jquery: '/lib/jquery.js',
                        jquery_rest: '/lib/jquery.rest.js',
                        wikistyles: '/static/wikistyles.css',
                        wikifunctions: '/static/wikifunctions.js'};

require('domo').global();

var filesystem = require('fs'),
  pagedown = require('pagedown'),
  restify = require('restify'),
  git = require('gitty'),
  mimeparse = require('mimeparse'),
  bunyan = require('bunyan');

var logger = bunyan.createLogger({    // @issue stuff logged with logger.debug somehow doesn't appear at all...
  name: 'rswiki',
  stream: process.stdout,
  src: true
});

/***********************************************************
 * Function definitions
 **********************************************************/

//////////////////// REST-API

/**
 * Loads the contents of a wikipage (in markdown) from storage.
 *
 * @param   {restify.Request}   req   Request-object given by restify
 * @param   {restify.Response}  res   Response-object given by restify
 * @param   {Function}          next  Next callback in the chain to call
 * @returns {Object}            The return-value of the next callback in the chain or an Error if something failed.
 */
var api_getPage = function api_getPage (req, res, next) {
  var pageName = req.params.name;
  var fileName = WIKIDATA + '/' + pageName + '.md';

  logger.info({fileName: fileName, page: {name: pageName}}, 'api_getPage: %s', pageName);

  filesystem.exists(fileName, function _fsExists (exists) {
    if (exists) {
      filesystem.readFile(fileName, 'utf8', function _readErr (err, file) {
        if (err) {
          logger.error({error: err, fileName: fileName, page: {name: pageName}}, 'Error occured while loading page %s : %s', pageName, err);
          return next(err);
        } else {
          return next({page: {content: file, name: req.params.name}});
        }
      });
    } else {
      logger.info({fileName: fileName, page: {name: pageName}}, 'Page %s does not exist, returning "null"-content.', pageName);
      return next({page: {content: null, name: pageName}});
    }
  });
};

/**
 * Saves the contents (markdown) of a wikipage to the storage and performs a git-commit.
 *
 * @param   {restify.Request}   req   Request-object given by restify
 * @param   {restify.Response}  res   Response-object given by restify
 * @param   {Function}          next  Next callback in the chain to call
 * @returns {Object}            Forwards to api_getPage WITHOUT returning it (api_getPage calls next callback) or an Error if something fails.
 */
var api_savePage = function api_savePage (req, res, next) {
  var pageName = req.params.name;
  var page = req.params.page;
  var fileName = WIKIDATA + '/' + pageName + '.md';

  logger.info({fileName: fileName, page: {name: pageName}}, 'api_savePage: %s', pageName);

  // @todo synchronize the whole thing somehow?
  filesystem.writeFile(fileName, page.content, 'utf8', function _writeErr(err) {
    if (err) {
      logger.error({error: err, fileName: fileName, page: {name: pageName}}, 'Error occured while writing page %s : %s', pageName, err);
      return next(err);
    } else {
      var repo = new git.Repository(WIKIDATA);
      var gitFiles = [pageName + '.md'];

//      git.config('user.name', data.user.name, function _gitConfigNameErr (err) {   // @bug overrides global config
//        if (gitSuccess(err, callback)) {
//          git.config('user.email', data.user.email, function _gitConfigEMail(err) {
//            if (gitSuccess(err, callback)) {
              repo.add(gitFiles, function _gitAddErr (err) {
                if (err) {
                  logger.error({error: err, fileName: fileName, page: {name: pageName}}, 'Error occured while adding to git, trying to unstage: %s', err);
                  repo.unstage(gitFiles, function _gitUnstageErr (err) {
                      if(err) {
                        logger.error({error: err, fileName: fileName, page: {name: pageName}}, 'Error occured while unstaging: %s', err);
                        return next(err);
                      }
                    });
                  return next(err);
                } else {
                  repo.commit(page.changeMessage, function _gitCommitErr (err) {
                    if (err) {
                      logger.error({error: err, fileName: fileName, page: {name: pageName}}, 'Error occured while commiting to git, trying to unstage: %s', err);
                      repo.unstage(gitFiles, function _gitUnstageErr (err) {
                          if (err) {
                            logger.error({error: err, fileName: fileName, page: {name: pageName}}, 'Error occured while unstaging: %s', err);
                            return next(err);
                          }
                        });
                      return next(err);
                    } else {
                      logger.info({fileName: fileName, page: {name: pageName}}, 'Successfully committed page %s.', pageName);
                    }
                  });
                }
              });
//            }
//          });
//        }
//      });
    }
  });

  api_getPage(req, res, next);    // reload page from storage and give it back to caller
};

/**
 * Deletes a page from the storage and from git.
 *
 * @param   {restify.Request}   req   Request-object given by restify
 * @param   {restify.Response}  res   Response-object given by restify
 * @param   {Function}          next  Next callback in the chain to call
 * @returns {Object}            The return-value of the next callback in the chain or an Error if something failed.
 */
var api_deletePage = function api_deletePage (req, res, next) {
  var pageName = req.params.name;
  var page = req.params.page;
  var fileName = WIKIDATA + '/' + pageName + '.md';

  var repo = new git.Repository(WIKIDATA);
  var gitFiles = [pageName + '.md'];

  logger.info({fileName: fileName, page: {name: pageName}}, 'api_deletePage: %s', pageName);

//  git.config('user.name', data.user.name, function _gitConfigNameErr (err) {   // @bug overrides global config
//    if (gitSuccess(err, callback)) {
//      git.config('user.email', data.user.email, function _gitConfigEMailErr (err) {
//        if (gitSuccess(err, callback)) {
          repo.remove(gitFiles, function _gitRemoveErr (err) {
            if (err) {
              logger.error({error: err, fileName: fileName, page: {name: pageName}}, 'Error while removing page %s from git: %s', pageName, err);
              return next(err);
            } else {
              repo.commit(page.changeMessage, function _gitCommitErr (err) {
                if (err) {
                  logger.error({error: err, fileName: fileName, page: {name: pageName}}, 'Error while committing to git: %s', err);
                  return next(err);
                } else {
                  filesystem.unlink(fileName, function _unlinkErr (err) {
                    if (err) {
                      logger.error({error: err, fileName: fileName, page: {name: pageName}}, 'Error while deleting page %s : %s', pageName, err);
                      return next(err);
                    } else {
                      logger.info({fileName: fileName, page: {name: pageName}}, 'Successfully deleted page %s.', pageName);
                      return next({page: {content: null, name: pageName}});
                    }
                  });
                }
              });
            }
          });
//        }
//      });
//    }
//  });
};

//////////////////// output-formatters

/**
 * Formatter called by restify when requestor wants text/html.
 *
 * @param   {restify.Request}   req   Request-object given by restify
 * @param   {restify.Response}  res   Response-object given by restify
 * @param   {Object}            body  The effective wiki-page as returned by the api_*-methods as JSON.
 * @returns {String}            HTML-representation of the page (or the Error)
 */
var fmt_Html = function fmt_Html (req, res, body) {

  if (body instanceof Error) {

    return DOCUMENT(
      HTML({lang: 'en'},
        HEAD(
          META({charset: 'utf-8'}),
          TITLE(body.statusCode ? body.statusCode  + ': ' + body.message : body.message)
        ),
        BODY(
          DIV({id: 'rswiki_error'}, (body.statusCode ? body.statusCode  + ': ' + body.message : body.message))
        )
      )
    ).outerHTML + '\n';

  } else {

    var pageContent;
    if (body.page.content) {
      pageContent = pagedown.getSanitizingConverter().makeHtml(body.page.content);   // or: new pagedown.Converter();
    } else {
      pageContent = '';
    }

    return DOCUMENT(
      HTML({lang: 'en'},
        HEAD(
          META({charset: 'utf-8'}),
          TITLE(body.page.name),
          LINK({rel: 'stylesheet', type: 'text/css', href: CLIENTRESOURCES.wikistyles}),
          SCRIPT({src: CLIENTRESOURCES.domo}),
          SCRIPT({src: CLIENTRESOURCES.md_converter}),
          SCRIPT({src: CLIENTRESOURCES.md_sanitizer}),
          SCRIPT({src: CLIENTRESOURCES.md_editor}),
          SCRIPT({src: CLIENTRESOURCES.jquery}),
          SCRIPT({src: CLIENTRESOURCES.jquery_rest}),
          SCRIPT({src: CLIENTRESOURCES.wikifunctions})
        ),
        BODY(
          DIV({id: 'rswiki_header'},
            DIV({id: 'rswiki_title'}, body.page.name),
            DIV({id: 'rswiki_navi'},
              A({id: 'rswiki_button_edit', href: '#'}, 'edit'),
              SPAN({id: 'rswiki_button_delete'}, ' | ', A({href: '#'}, 'delete'))
            )
          ),
          DIV({id: 'rswiki_editor'}),
          DIV({id: 'rswiki_content'}, '%#%PAGECONTENT%#%')
        )
      )
    ).outerHTML.replace('%#%PAGECONTENT%#%', pageContent) + '\n';   // or: new pagedown.Converter();

  }
};

/**
 * Formatter called by restify when requestor wants text/plain.
 *
 * @param   {restify.Request}   req   Request-object given by restify
 * @param   {restify.Response}  res   Response-object given by restify
 * @param   {Object}            body  The effective wiki-page as returned by the api_*-methods as JSON.
 * @returns {String}            Plaintext-representation of the page (or the Error)
 */
var fmt_Text = function fmt_Text (req, res, body) {
  if (body instanceof Error) {
    return 'Error!\n\n' +
      (body.statusCode ? 'Statuscode: ' + body.statusCode + '\n' : '') +
      'Message: ' + body.message + '\n';
  } else {
    return 'Title: ' + body.page.name +
      '\n------------------ START CONTENT --------------------\n' +
      body.page.content +
      '\n------------------- END CONTENT ---------------------\n';
  }
};

/***********************************************************
 * Main application
 **********************************************************/

//////////////////// setup server

var server = restify.createServer({
  formatters: {
    'text/html': fmt_Html,
    'text/plain': fmt_Text
//    'text/x-markdown': fmt_Markdown   @todo implement text/x-markdown
    // application/json gets implicitly handled by restify
  }
});  // @todo SSL...

//// server: events
if (AUDITLOG) {
  server.on('after', restify.auditLogger({log: logger}));
}

// @issue workaround for seemingly improper accept-header-evaluation by restify...
server.pre(function _mimeFix (req, res, next) {
  req.headers.accept = mimeparse.bestMatch(['text/plain','text/html','application/json'], req.headers.accept);
  return next();
});

//// server: general handlers
server.use(restify.requestLogger());    // @issue requestLogger logs NOTHING!
server.use(restify.bodyParser());
server.use(restify.acceptParser(server.acceptable));

//// server: static content
server.get(/\/static\/?.*/, restify.serveStatic({directory: '.'}));   // @issue serveStatic doesn't emit NotFound-event...
server.get(/\/lib\/?.*/, restify.serveStatic({directory: '.'}));
server.get(/\/node_modules\/?.*/, restify.serveStatic({directory: '.'}));

//// server: page API
server.get(PAGEPREFIX + '/:name', api_getPage);   // @todo GET redirect / to a mainpage or provide a list of pages?
server.put(PAGEPREFIX + '/:name', api_savePage);
server.post(PAGEPREFIX + '/:name', api_savePage);
server.del(PAGEPREFIX + '/:name', api_deletePage);

//// start server
server.listen(LISTENPORT, function listenCallback () {
  logger.info({serverName: server.name, serverURL: server.url}, '%s listening at %s.', server.name, server.url);
});
<|endoftext|>


<commit_before>$(function() {

    $("#contactForm input,#contactForm textarea").jqBootstrapValidation({
        preventSubmit: true,
        submitError: function($form, event, errors) {
            // additional error messages or events
        },
        submitSuccess: function($form, event) {
            event.preventDefault(); // prevent default submit behaviour
            // get values from FORM
            var name = $("input#name").val();
            var email = $("input#email").val();
            var phone = $("input#phone").val();
            var message = $("textarea#message").val();
            var firstName = name; // For Success/Failure Message
            // Check for white space in name for Success/Fail message
            if (firstName.indexOf(' ') >= 0) {
                firstName = name.split(' ').slice(0, -1).join(' ');
            }
            $.ajax({
                url: "././mail/contact_me.php",
                type: "POST",
                data: {
                    name: name,
                    email: email
                },
                cache: false,
                success: function() {
                    // Success message
                    $('#success').html("
");
                    $('#success > .alert-success').html("<button type='button' class='close' data-dismiss='alert' aria-hidden='true'>×")
                        .append("</button>");
                    $('#success > .alert-success')
                        .append("Your message has been sent. ");
                    $('#success > .alert-success')
                        .append('
');

                    //clear all fields
                    $('#contactForm').trigger("reset");
                },
                error: function() {
                    // Fail message
                    $('#success').html("
");
                    $('#success > .alert-danger').html("<button type='button' class='close' data-dismiss='alert' aria-hidden='true'>×")
                        .append("</button>");
                    $('#success > .alert-danger').append("Sorry " + firstName + ", it seems that my mail server is not responding. Please try again later!");
                    $('#success > .alert-danger').append('
');
                    //clear all fields
                    $('#contactForm').trigger("reset");
                },
            })
        },
        filter: function() {
            return $(this).is(":visible");
        },
    });

    $("a[data-toggle=\"tab\"]").click(function(e) {
        e.preventDefault();
        $(this).tab("show");
    });
});

/*When clicking on Full hide fail/success boxes */
$('#name').focus(function() {
    $('#success').html('');
});
<commit_msg>Update contact_me.js<commit_after>$(function() {

    $("#contactForm input,#contactForm textarea").jqBootstrapValidation({
        preventSubmit: true,
        submitError: function($form, event, errors) {
            // additional error messages or events
        },
        submitSuccess: function($form, event) {
            event.preventDefault(); // prevent default submit behaviour
            // get values from FORM
            var name = $("input#name").val();
            var email = $("input#email").val();
            var phone = $("input#phone").val();
            var message = $("textarea#message").val();
            var firstName = name; // For Success/Failure Message
            // Check for white space in name for Success/Fail message
            if (firstName.indexOf(' ') >= 0) {
                firstName = name.split(' ').slice(0, -1).join(' ');
            }
            $.ajax({
                url: "././mail/contact_me.php",
                type: "POST",
                data: {
                    name: name,
                    email: email
                },
                dataType: 'json',
                cache: false,
                success: function() {
                    // Success message
                    $('#success').html("
");
                    $('#success > .alert-success').html("<button type='button' class='close' data-dismiss='alert' aria-hidden='true'>×")
                        .append("</button>");
                    $('#success > .alert-success')
                        .append("Your message has been sent. ");
                    $('#success > .alert-success')
                        .append('
');

                    //clear all fields
                    $('#contactForm').trigger("reset");
                },
                error: function() {
                    // Fail message
                    $('#success').html("
");
                    $('#success > .alert-danger').html("<button type='button' class='close' data-dismiss='alert' aria-hidden='true'>×")
                        .append("</button>");
                    $('#success > .alert-danger').append("Sorry " + firstName + ", it seems that my mail server is not responding. Please try again later!");
                    $('#success > .alert-danger').append('
');
                    //clear all fields
                    $('#contactForm').trigger("reset");
                },
            })
        },
        filter: function() {
            return $(this).is(":visible");
        },
    });

    $("a[data-toggle=\"tab\"]").click(function(e) {
        e.preventDefault();
        $(this).tab("show");
    });
});

/*When clicking on Full hide fail/success boxes */
$('#name').focus(function() {
    $('#success').html('');
});
<|endoftext|>