<commit_before>'use strict';

const http = require('http');
const BBPromise = require('bluebird');
const express = require('express');
const compression = require('compression');
const bodyParser = require('body-parser');
const fs = BBPromise.promisifyAll(require('fs'));
const sUtil = require('./lib/util');
const specLib = require('./lib/spec');
const apiUtil = require('./lib/api-util');
const mUtil = require('./lib/mobile-util');
const packageInfo = require('./package.json');
const yaml = require('js-yaml');
const addShutdown = require('http-shutdown');
const path = require('path');

const MAX_STEPS_PER_TICK = 5;

/**
 * Creates an express app and initialises it
 * @param {!Object} options the options to initialise the app with
 * @return {!bluebird} the promise resolving to the app object
 */
function initApp(options) {

    // the main application object
    const app = express();

    // get the options and make them available in the app
    app.logger = options.logger;    // the logging device
    app.metrics = options.metrics;  // the metrics
    app.conf = options.config;      // this app's config options
    app.info = packageInfo;         // this app's package info

    // ensure some sane defaults
    if (!app.conf.port) {
        app.conf.port = 8888;
    }
    if (!app.conf.interface) {
        app.conf.interface = '0.0.0.0';
    }
    if (app.conf.compression_level === undefined) {
        app.conf.compression_level = 3;
    }
    if (app.conf.cors === undefined) {
        app.conf.cors = '*';
    }
    if (app.conf.csp === undefined) {
        // eslint-disable-next-line max-len
        app.conf.csp = "default-src 'self'; object-src 'none'; media-src *; img-src *; style-src *; frame-ancestors 'self'";
    }

   /**
    * script-src:
    *   The pagelib JavaScript bundle is served on meta.wikimedia.org.
    *   We also add a small piece of inline JS to the end of the body to trigger lazy-loading.
    * style-src:
    *   The site CSS bundle is served from the current domain (TODO: currently assumes WP).
    *   The base CSS bundle is served on meta.wikimedia.org.
    *   The pages also have some inline styles.
    * img-src:
    *   We need to specifically allow data: URIs for the buttons from the wikimedia-page-library.
    */
    if (app.conf.mobile_html_csp === undefined) {
        // eslint-disable-next-line max-len
        app.conf.mobile_html_csp = "default-src 'none'; connect-src https://*.wikipedia.org; media-src *; img-src * data:; script-src app://meta.wikimedia.org https://meta.wikimedia.org" +
            " 'unsafe-inline'; style-src app://meta.wikimedia.org https://meta.wikimedia.org app://*.wikipedia.org https://*.wikipedia.org 'self' 'unsafe-inline'; frame-ancestors 'self'";
    }

    if (app.conf.mobile_html_rest_api_base_uri === undefined) {
        // eslint-disable-next-line max-len
        app.conf.mobile_html_rest_api_base_uri = 'https://meta.wikimedia.org/api/rest_v1/';
    }

    // set outgoing proxy
    if (app.conf.proxy) {
        process.env.HTTP_PROXY = app.conf.proxy;
        // if there is a list of domains which should
        // not be proxied, set it
        if (app.conf.no_proxy_list) {
            if (Array.isArray(app.conf.no_proxy_list)) {
                process.env.NO_PROXY = app.conf.no_proxy_list.join(',');
            } else {
                process.env.NO_PROXY = app.conf.no_proxy_list;
            }
        }
    }

    // set up header whitelisting for logging
    if (!app.conf.log_header_whitelist) {
        app.conf.log_header_whitelist = [
            'cache-control', 'content-type', 'content-length', 'if-match',
            'user-agent', 'x-request-id'
        ];
    }
    app.conf.log_header_whitelist = new RegExp(`^(?:${app.conf.log_header_whitelist.map((item) => {
        return item.trim();
    }).join('|')})$`, 'i');

    // set up the request templates for the APIs
    apiUtil.setupApiTemplates(app);

    // set up the spec
    if (!app.conf.spec) {
        app.conf.spec = specLib.load(`${__dirname}/spec`, {});
    }
    if (app.conf.spec.constructor !== Object) {
        try {
            app.conf.spec = yaml.safeLoad(fs.readFileSync(app.conf.spec));
        } catch (e) {
            app.logger.log('warn/spec', `Could not load the spec: ${e}`);
            app.conf.spec = {};
        }
    }
    if (!app.conf.spec.openapi) {
        app.conf.spec.openapi = '3.0.1';
    }
    if (!app.conf.spec.info) {
        app.conf.spec.info = {
            version: app.info.version,
            title: app.info.name,
            description: app.info.description
        };
    }
    app.conf.spec.info.version = app.info.version;
    if (!app.conf.spec.paths) {
        app.conf.spec.paths = {};
    }

    // set the CORS and CSP headers
    app.all('*', (req, res, next) => {
        if (app.conf.cors !== false) {
            res.header('access-control-allow-origin', app.conf.cors);
            res.header('access-control-allow-headers', 'accept, x-requested-with, content-type');
            res.header('access-control-expose-headers', 'etag');
        }
        if (app.conf.csp !== false) {
            res.header('x-xss-protection', '1; mode=block');
            res.header('x-content-type-options', 'nosniff');
            res.header('x-frame-options', 'SAMEORIGIN');
            mUtil.setContentSecurityPolicy(res, app.conf.csp);
        }
        sUtil.initAndLogRequest(req, app);
        next();
    });

    // set up the user agent header string to use for requests
    app.conf.user_agent = app.conf.user_agent || app.info.name;

    // disable the X-Powered-By header
    app.set('x-powered-by', false);
    // disable the ETag header - users should provide them!
    app.set('etag', false);
    // enable compression
    app.use(compression({ level: app.conf.compression_level }));
    // use the JSON body parser
    app.use(bodyParser.json({ limit: app.conf.max_body_size || '100kb' }));
    // use the application/x-www-form-urlencoded parser
    app.use(bodyParser.urlencoded({ extended: true }));
    // use text for text/html
    app.use(bodyParser.text({ type: 'text/html', limit: '10MB' }));

    return BBPromise.resolve(app);

}

/**
 * Loads all routes declared in routes/ into the app
 * @param {Application} app the application object to load routes into
 * @param {string} dir routes folder
 * @return {bluebird} a promise resolving to the app object
 */
function loadRoutes(app, dir) {

    // recursively load routes from .js files under routes/
    return fs.readdirAsync(dir).map((fname) => {
        return BBPromise.try(() => {
            const resolvedPath = path.resolve(dir, fname);
            const isDirectory = fs.statSync(resolvedPath).isDirectory();
            if (isDirectory) {
                loadRoutes(app, resolvedPath);
            } else if (/\.js$/.test(fname)) {
                // import the route file
                const route = require(`${dir}/${fname}`);
                return route(app);
            }
        }).then((route) => {
            if (route === undefined) {
                return undefined;
            }
            // check that the route exports the object we need
            if (route.constructor !== Object || !route.path || !route.router ||
                !(route.api_version || route.skip_domain)) {
                throw new TypeError(`routes/${fname} does not export the correct object!`);
            }
            // normalise the path to be used as the mount point
            if (route.path[0] !== '/') {
                route.path = `/${route.path}`;
            }
            if (route.path[route.path.length - 1] !== '/') {
                route.path = `${route.path}/`;
            }
            if (!route.skip_domain) {
                route.path = `/:domain/v${route.api_version}${route.path}`;
            }
            // wrap the route handlers with Promise.try() blocks
            sUtil.wrapRouteHandlers(route, app);
            // all good, use that route
            app.use(route.path, route.router);
        });
    }).then(() => {
        // catch errors
        sUtil.setErrorHandler(app);
        // route loading is now complete, return the app object
        return BBPromise.resolve(app);
    });

}

/**
 * Preload scripts for preprocessing Parsoid HTML for page content endpoints
 * @param {Application} app the app object to use in the service
 * @return {bluebird} a promise resolving to the app object, with preprocessing scripts attached
 */
function loadPreProcessingScripts(app, dir) {

    /**
     * Break down array into chunks of the specified size
     * @param {!Array} arr array
     * @param {!integer} size chunk size
     */
    function _chunk(arr, size) {
        return arr.reduce((acc, cur, idx) => {
            const i = Math.floor(idx / size);
            if (!acc[i]) {
                acc[i] = [];
            }
            acc[i].push(cur);
            return acc;
        }, []);
    }

    /**
     * Validate the script format
     * @param {!Array} script processing script
     * @throws error if script format is invalid
     */
    function _validate(script) {
        if (script.filter((i) => {
            return typeof i === 'object' && Object.keys(i).length !== 1;
        }).length) {
            throw new Error('Invalid processing script format');
        }
    }

    app.conf.processing_scripts = {};
    return fs.readdirAsync(dir).map(filename => BBPromise.try(() => {
        const name = filename.split('.')[0];
        let script = yaml.safeLoad(fs.readFileSync(`${dir}/${filename}`));
        _validate(script);
        script = _chunk(script, MAX_STEPS_PER_TICK);
        app.conf.processing_scripts[name] = script;
    })
    .catch(e => app.logger.log('warn/loading', `Error loading processing scripts: ${e}`)))
    .then(() => BBPromise.resolve(app));
}

/**
 * Creates and start the service's web server
 * @param {Application} app the app object to use in the service
 * @return {bluebird} a promise creating the web server
 */
function createServer(app) {

    // return a promise which creates an HTTP server,
    // attaches the app to it, and starts accepting
    // incoming client requests
    let server;
    return new BBPromise((resolve) => {
        server = http.createServer(app).listen(
            app.conf.port,
            app.conf.interface,
            resolve
        );
        server = addShutdown(server);
    }).then(() => {
        app.logger.log('info',
            `Worker ${process.pid} listening on ${app.conf.interface || '*'}:${app.conf.port}`);

        // Don't delay incomplete packets for 40ms (Linux default) on
        // pipelined HTTP sockets. We write in large chunks or buffers, so
        // lack of coalescing should not be an issue here.
        server.on('connection', (socket) => {
            socket.setNoDelay(true);
        });

        return server;
    });

}

/**
 * The service's entry point. It takes over the configuration
 * options and the logger- and metrics-reporting objects from
 * service-runner and starts an HTTP server, attaching the application
 * object to it.
 * @param {Object} options the options to initialise the app with
 * @return {bluebird} HTTP server
 */
module.exports = (options) => {

    return initApp(options)
    .then(app => loadRoutes(app, `${__dirname}/routes`))
    .then(app => loadPreProcessingScripts(app, `${__dirname}/processing`))
    .then((app) => {
        // serve static files from static/
        app.use('/static', express.static(`${__dirname}/static`));
        return app;
    }).then(createServer);

};
<commit_msg>Hygiene: reformat mobile-html CSP header<commit_after>'use strict';

const http = require('http');
const BBPromise = require('bluebird');
const express = require('express');
const compression = require('compression');
const bodyParser = require('body-parser');
const fs = BBPromise.promisifyAll(require('fs'));
const sUtil = require('./lib/util');
const specLib = require('./lib/spec');
const apiUtil = require('./lib/api-util');
const mUtil = require('./lib/mobile-util');
const packageInfo = require('./package.json');
const yaml = require('js-yaml');
const addShutdown = require('http-shutdown');
const path = require('path');

const MAX_STEPS_PER_TICK = 5;

/**
 * Creates an express app and initialises it
 * @param {!Object} options the options to initialise the app with
 * @return {!bluebird} the promise resolving to the app object
 */
function initApp(options) {

    // the main application object
    const app = express();

    // get the options and make them available in the app
    app.logger = options.logger;    // the logging device
    app.metrics = options.metrics;  // the metrics
    app.conf = options.config;      // this app's config options
    app.info = packageInfo;         // this app's package info

    // ensure some sane defaults
    if (!app.conf.port) {
        app.conf.port = 8888;
    }
    if (!app.conf.interface) {
        app.conf.interface = '0.0.0.0';
    }
    if (app.conf.compression_level === undefined) {
        app.conf.compression_level = 3;
    }
    if (app.conf.cors === undefined) {
        app.conf.cors = '*';
    }
    if (app.conf.csp === undefined) {
        // eslint-disable-next-line max-len
        app.conf.csp = "default-src 'self'; object-src 'none'; media-src *; img-src *; style-src *; frame-ancestors 'self'";
    }

   /**
    * script-src:
    *   The pagelib JavaScript bundle is served on meta.wikimedia.org.
    *   We also add a small piece of inline JS to the end of the body to trigger lazy-loading.
    * style-src:
    *   The site CSS bundle is served from the current domain (TODO: currently assumes WP).
    *   The base CSS bundle is served on meta.wikimedia.org.
    *   The pages also have some inline styles.
    * img-src:
    *   We need to specifically allow data: URIs for the buttons from the wikimedia-page-library.
    */
    if (app.conf.mobile_html_csp === undefined) {
        // eslint-disable-next-line max-len
        app.conf.mobile_html_csp = "default-src 'none'; connect-src https://*.wikipedia.org; media-src *; img-src * data:; " +
            "script-src app://meta.wikimedia.org https://meta.wikimedia.org 'unsafe-inline'; " +
            "style-src app://meta.wikimedia.org https://meta.wikimedia.org app://*.wikipedia.org https://*.wikipedia.org 'self' 'unsafe-inline'; " +
            "frame-ancestors 'self'";
    }

    if (app.conf.mobile_html_rest_api_base_uri === undefined) {
        // eslint-disable-next-line max-len
        app.conf.mobile_html_rest_api_base_uri = 'https://meta.wikimedia.org/api/rest_v1/';
    }

    // set outgoing proxy
    if (app.conf.proxy) {
        process.env.HTTP_PROXY = app.conf.proxy;
        // if there is a list of domains which should
        // not be proxied, set it
        if (app.conf.no_proxy_list) {
            if (Array.isArray(app.conf.no_proxy_list)) {
                process.env.NO_PROXY = app.conf.no_proxy_list.join(',');
            } else {
                process.env.NO_PROXY = app.conf.no_proxy_list;
            }
        }
    }

    // set up header whitelisting for logging
    if (!app.conf.log_header_whitelist) {
        app.conf.log_header_whitelist = [
            'cache-control', 'content-type', 'content-length', 'if-match',
            'user-agent', 'x-request-id'
        ];
    }
    app.conf.log_header_whitelist = new RegExp(`^(?:${app.conf.log_header_whitelist.map((item) => {
        return item.trim();
    }).join('|')})$`, 'i');

    // set up the request templates for the APIs
    apiUtil.setupApiTemplates(app);

    // set up the spec
    if (!app.conf.spec) {
        app.conf.spec = specLib.load(`${__dirname}/spec`, {});
    }
    if (app.conf.spec.constructor !== Object) {
        try {
            app.conf.spec = yaml.safeLoad(fs.readFileSync(app.conf.spec));
        } catch (e) {
            app.logger.log('warn/spec', `Could not load the spec: ${e}`);
            app.conf.spec = {};
        }
    }
    if (!app.conf.spec.openapi) {
        app.conf.spec.openapi = '3.0.1';
    }
    if (!app.conf.spec.info) {
        app.conf.spec.info = {
            version: app.info.version,
            title: app.info.name,
            description: app.info.description
        };
    }
    app.conf.spec.info.version = app.info.version;
    if (!app.conf.spec.paths) {
        app.conf.spec.paths = {};
    }

    // set the CORS and CSP headers
    app.all('*', (req, res, next) => {
        if (app.conf.cors !== false) {
            res.header('access-control-allow-origin', app.conf.cors);
            res.header('access-control-allow-headers', 'accept, x-requested-with, content-type');
            res.header('access-control-expose-headers', 'etag');
        }
        if (app.conf.csp !== false) {
            res.header('x-xss-protection', '1; mode=block');
            res.header('x-content-type-options', 'nosniff');
            res.header('x-frame-options', 'SAMEORIGIN');
            mUtil.setContentSecurityPolicy(res, app.conf.csp);
        }
        sUtil.initAndLogRequest(req, app);
        next();
    });

    // set up the user agent header string to use for requests
    app.conf.user_agent = app.conf.user_agent || app.info.name;

    // disable the X-Powered-By header
    app.set('x-powered-by', false);
    // disable the ETag header - users should provide them!
    app.set('etag', false);
    // enable compression
    app.use(compression({ level: app.conf.compression_level }));
    // use the JSON body parser
    app.use(bodyParser.json({ limit: app.conf.max_body_size || '100kb' }));
    // use the application/x-www-form-urlencoded parser
    app.use(bodyParser.urlencoded({ extended: true }));
    // use text for text/html
    app.use(bodyParser.text({ type: 'text/html', limit: '10MB' }));

    return BBPromise.resolve(app);

}

/**
 * Loads all routes declared in routes/ into the app
 * @param {Application} app the application object to load routes into
 * @param {string} dir routes folder
 * @return {bluebird} a promise resolving to the app object
 */
function loadRoutes(app, dir) {

    // recursively load routes from .js files under routes/
    return fs.readdirAsync(dir).map((fname) => {
        return BBPromise.try(() => {
            const resolvedPath = path.resolve(dir, fname);
            const isDirectory = fs.statSync(resolvedPath).isDirectory();
            if (isDirectory) {
                loadRoutes(app, resolvedPath);
            } else if (/\.js$/.test(fname)) {
                // import the route file
                const route = require(`${dir}/${fname}`);
                return route(app);
            }
        }).then((route) => {
            if (route === undefined) {
                return undefined;
            }
            // check that the route exports the object we need
            if (route.constructor !== Object || !route.path || !route.router ||
                !(route.api_version || route.skip_domain)) {
                throw new TypeError(`routes/${fname} does not export the correct object!`);
            }
            // normalise the path to be used as the mount point
            if (route.path[0] !== '/') {
                route.path = `/${route.path}`;
            }
            if (route.path[route.path.length - 1] !== '/') {
                route.path = `${route.path}/`;
            }
            if (!route.skip_domain) {
                route.path = `/:domain/v${route.api_version}${route.path}`;
            }
            // wrap the route handlers with Promise.try() blocks
            sUtil.wrapRouteHandlers(route, app);
            // all good, use that route
            app.use(route.path, route.router);
        });
    }).then(() => {
        // catch errors
        sUtil.setErrorHandler(app);
        // route loading is now complete, return the app object
        return BBPromise.resolve(app);
    });

}

/**
 * Preload scripts for preprocessing Parsoid HTML for page content endpoints
 * @param {Application} app the app object to use in the service
 * @return {bluebird} a promise resolving to the app object, with preprocessing scripts attached
 */
function loadPreProcessingScripts(app, dir) {

    /**
     * Break down array into chunks of the specified size
     * @param {!Array} arr array
     * @param {!integer} size chunk size
     */
    function _chunk(arr, size) {
        return arr.reduce((acc, cur, idx) => {
            const i = Math.floor(idx / size);
            if (!acc[i]) {
                acc[i] = [];
            }
            acc[i].push(cur);
            return acc;
        }, []);
    }

    /**
     * Validate the script format
     * @param {!Array} script processing script
     * @throws error if script format is invalid
     */
    function _validate(script) {
        if (script.filter((i) => {
            return typeof i === 'object' && Object.keys(i).length !== 1;
        }).length) {
            throw new Error('Invalid processing script format');
        }
    }

    app.conf.processing_scripts = {};
    return fs.readdirAsync(dir).map(filename => BBPromise.try(() => {
        const name = filename.split('.')[0];
        let script = yaml.safeLoad(fs.readFileSync(`${dir}/${filename}`));
        _validate(script);
        script = _chunk(script, MAX_STEPS_PER_TICK);
        app.conf.processing_scripts[name] = script;
    })
    .catch(e => app.logger.log('warn/loading', `Error loading processing scripts: ${e}`)))
    .then(() => BBPromise.resolve(app));
}

/**
 * Creates and start the service's web server
 * @param {Application} app the app object to use in the service
 * @return {bluebird} a promise creating the web server
 */
function createServer(app) {

    // return a promise which creates an HTTP server,
    // attaches the app to it, and starts accepting
    // incoming client requests
    let server;
    return new BBPromise((resolve) => {
        server = http.createServer(app).listen(
            app.conf.port,
            app.conf.interface,
            resolve
        );
        server = addShutdown(server);
    }).then(() => {
        app.logger.log('info',
            `Worker ${process.pid} listening on ${app.conf.interface || '*'}:${app.conf.port}`);

        // Don't delay incomplete packets for 40ms (Linux default) on
        // pipelined HTTP sockets. We write in large chunks or buffers, so
        // lack of coalescing should not be an issue here.
        server.on('connection', (socket) => {
            socket.setNoDelay(true);
        });

        return server;
    });

}

/**
 * The service's entry point. It takes over the configuration
 * options and the logger- and metrics-reporting objects from
 * service-runner and starts an HTTP server, attaching the application
 * object to it.
 * @param {Object} options the options to initialise the app with
 * @return {bluebird} HTTP server
 */
module.exports = (options) => {

    return initApp(options)
    .then(app => loadRoutes(app, `${__dirname}/routes`))
    .then(app => loadPreProcessingScripts(app, `${__dirname}/processing`))
    .then((app) => {
        // serve static files from static/
        app.use('/static', express.static(`${__dirname}/static`));
        return app;
    }).then(createServer);

};
<|endoftext|>


<commit_before>var ext = require('./extract-content-all'),
    ex = new ext.ExtractContentJS.LayeredExtractor(),
    request = require('request'),
    jsdom = require('jsdom'),
    Iconv  = require('iconv').Iconv,
    app = require('express').createServer(),
    Buffer = require('buffer').Buffer;

ex.addHandler(ex.factory.getHandler('Heuristics'));
url = 'http://www.aichan.biz/html/html/h.html';
// url = 'http://d.hatena.ne.jp/hokaccha/20110801/1312216630'

/*
        var iconv  = new Iconv("Shift-JIS", 'UTF-8//TRANSLIT//IGNORE');
        console.log((iconv.convert(res.title)).toString());
        console.log((iconv.convert(res.content.toString())).toString());
        console.log(res.content.main_image(jsdom));
*/

app.get('/*', function(req, res){
    if (req.url.match(/^\/http.?:\/\/.*/)) {
        url = req.url.replace(/^\//, "");
        request(url, function (error, response, body) {
            if (!error && response.statusCode == 200) {
                var document = jsdom.jsdom(body);
                document.location = {};
                url = response.request.uri.href;
                document.location.href = url;
                var result = ex.extract(document, url);
                res.json({title: result.title, url:url, content:result.content.toString(), images: result.content.main_image(jsdom)});
            }else{
                return null;
            }
        });
    }else{
        res.writeHead(404, {'Content-Type':'application/json; charset=utf-8'});
        res.end('Not found');
    }
});
app.listen(3000);
<commit_msg>Save to mongodb<commit_after>var ext = require('./extract-content-all'),
    ex = new ext.ExtractContentJS.LayeredExtractor(),
    request = require('request'),
    jsdom = require('jsdom'),
    app = require('express').createServer(),
    mongoose = require('mongoose'),
    Iconv  = require('iconv').Iconv,
    Buffer = require('buffer').Buffer;

// url = 'http://www.aichan.biz/html/html/h.html';
// url = 'http://d.hatena.ne.jp/hokaccha/20110801/1312216630'

var Schema   = mongoose.Schema;
var UrlSchema = new Schema({
    title: String,
    content: String,
    images: [String],
    html: String,
    created: { type: Date, default: Date.now },
    updated: { type: Date, default: Date.now },
    url: String,
    urls: [String]
});
mongoose.model('Url', UrlSchema);
mongoose.connect('mongodb://localhost/linter');

app.enable('jsonp callback');
app.get('/', function(req, res){
    url = req.query.url ? req.query.url.replace(/^\//, "") : "";
    if (!url.match(/^http.?:\/\/.*/)) {
        return res.json({message: "Not found"+url, status: 404});
    }
    Url = mongoose.model('Url');
    Url.find({url: url}, function (err, docs) {
        if (typeof docs[0] != "undefined") {
            doc = docs[0];
            return res.json({title: doc.title, url:doc.url, content:doc.content, images: doc.images});
        }
        request(url, function (error, response, body) {
            if (error || response.statusCode != 200) {
                return res.json({message: error, status: response.statusCode});
            }
            var document = jsdom.jsdom(body);
            document.location = {};
            url = response.request.uri.href;
            document.location.href = url;
            ex.addHandler(ex.factory.getHandler('Heuristics'));
            var result = ex.extract(document, url);
            var new_url = new Url({title: result.title, url: url, content:result.content.toString()});
            new_url.urls.push(url);
            var images = result.content.main_image(jsdom);
            for (var i = 0; i <= images.length; i++){
                new_url.images.push(images[i]);
            }
            new_url.save(function(err){
                if (err) { console.log(err); }
            });
            res.json({title: result.title, url:url, content:result.content.toString(), images: result.content.main_image(jsdom)});
        });
    });
});
app.listen(3000);
<|endoftext|>


<commit_before>var express = require('express');
var app = express();

app.use(express.static(__dirname + '/public'));

var port = process.env.PORT || 8989;

var server = app.listen(port);

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

var farms = {};

var Farm = function(pw, row, col) {
	this.gold = 100;
	this.farm = [];
	for (var i = 0; i < row; i++) {
		this.farm.push([]);
		for (var j = 0; j < col; j++) {
			this.farm[i].push({row:i, col:j});
		}
	}
	this.inventory = [];
	this.inventory.push({plant: new Plant(), quantity: 3});
	this.password = pw;
};

var Plant = function() {
	this.name = "carrot";
	this.age = 0;
	this.ripetime = 10;
	this.yield = 0;
	this.color = "#FF0000";
	this.shape = 0;
	this.hash = this.name+this.ripetime+this.yield+this.color+this.shape;
};

console.log("Farmland is running on port 8989");
/*
   var farm = new Farm();
   farms["William"] = farm;
   console.log(new Farm());
   plant("William", new Plant(), 3, 3);
   pick("William", 3, 3);
   grow()
   console.log(farms);*/

function plant(owner, plant, row, col) {
	if (farms[owner].farm[row][col].hash != undefined) {
		plant.row = row;
		plant.col = col;
		farms[owner].farm[row][col] = plant;
		return true;
	}
	return false;
}

function pick(owner, row, col) {
	if (farms[owner].farm[row][col].hash != undefined && farms[owner].farm[row][col].age > farms[owner].farm[row][col].ripetime) {
		farms[owner].inventory.push(farms[owner].farm[row][col]);
		farms[owner].farm[row][col] = {row: row, col: col};
		return true;
	}
	return false;
}

function grow() {
	var keys = Object.keys(farms);
	keys.forEach(function(key) {
		if (farms[key]) {
			farms[key].farm.forEach(function(row) {
				row.forEach(function(plant) {
					if (plant.age !== undefined) {
						plant.age++;
					}
				});
			});
		}
	});
}

setInterval(grow, 1000);

io.on('connection', function(socket) {
  var name = "";
  socket.on("createFarm", function(nm, ps, cb) {
    name = nm;
    if (farms[nm] === undefined || farms[nm].password == ps) {
      var farm = new Farm(ps, 7, 7);
      farms[nm] = farm;
      cb(farm);
    } else {
      cb(false);
    }
  });
  socket.on("plant", function(nm, row, col, cb) {
    cb(plant(nm, row, col));
  });
  socket.on("pick", function(nm, row, col, cb) {
    cb(pick(nm, row, col));
  });
});
<commit_msg>what's a ps?<commit_after>var express = require('express');
var app = express();

app.use(express.static(__dirname + '/public'));

var port = process.env.PORT || 8989;

var server = app.listen(port);

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

var farms = {};

var Farm = function(pw, row, col) {
	this.gold = 100;
	this.farm = [];
	for (var i = 0; i < row; i++) {
		this.farm.push([]);
		for (var j = 0; j < col; j++) {
			this.farm[i].push({row:i, col:j});
		}
	}
	this.inventory = [];
	this.inventory.push({plant: new Plant(), quantity: 3});
	this.password = pw;
};

var Plant = function() {
	this.name = "carrot";
	this.age = 0;
	this.ripetime = 10;
	this.yield = 0;
	this.color = "#FF0000";
	this.shape = 0;
	this.hash = this.name+this.ripetime+this.yield+this.color+this.shape;
};

console.log("Farmland is running on port 8989");
/*
   var farm = new Farm();
   farms["William"] = farm;
   console.log(new Farm());
   plant("William", new Plant(), 3, 3);
   pick("William", 3, 3);
   grow()
   console.log(farms);*/

function plant(owner, plant, row, col) {
	if (farms[owner].farm[row][col].hash != undefined) {
		plant.row = row;
		plant.col = col;
		farms[owner].farm[row][col] = plant;
		return true;
	}
	return false;
}

function pick(owner, row, col) {
	if (farms[owner].farm[row][col].hash != undefined && farms[owner].farm[row][col].age > farms[owner].farm[row][col].ripetime) {
		farms[owner].inventory.push(farms[owner].farm[row][col]);
		farms[owner].farm[row][col] = {row: row, col: col};
		return true;
	}
	return false;
}

function grow() {
	var keys = Object.keys(farms);
	keys.forEach(function(key) {
		if (farms[key]) {
			farms[key].farm.forEach(function(row) {
				row.forEach(function(plant) {
					if (plant.age !== undefined) {
						plant.age++;
					}
				});
			});
		}
	});
}

setInterval(grow, 1000);

io.on('connection', function(socket) {
  var name = "";
  socket.on("createFarm", function(nm, pw, cb) {
    name = nm;
    if (farms[nm] === undefined || farms[nm].password == pw) {
      var farm = new Farm(pw, 7, 7);
      farms[nm] = farm;
      cb(farm);
    } else {
      cb(false);
    }
  });
  socket.on("plant", function(nm, row, col, cb) {
    cb(plant(nm, row, col));
  });
  socket.on("pick", function(nm, row, col, cb) {
    cb(pick(nm, row, col));
  });
});
<|endoftext|>


<commit_before>/*

   ebb chrome extension

   TODO:

   * incorporate handlebars for easier templating
   * gmail selectors for from, date, content body, etc
   * figure out how to scan a message body for dates
   * better load_complete support for gmail (everything is async)
   * try and get messageid from within gmail

*/

// --- Configuration
var options = {
  name: 'ebb',
  development: true,
  logLevel: 'debug',
  cssLink: 'styles/ebb.css',
  apiHost: 'http://ebb-when.herokuapp.com'
}

// --- Libraries

var Logger = function(options) {
  if (typeof(options) !== 'object')
    throw new TypeError('options (object) is required');

  if (!options.name)
    throw new TypeError('options.name (string) is required');

  var logLevels = [
    'INFO',
    'DEBUG'
  ];

  this._name = options.name;
  this._level = options.level || 'INFO'

}

Logger.prototype.name = function() {
  return this._name;
}

Logger.prototype.level = function() {
  return this._level;
}

Logger.prototype._print = function(level, msg) {
  var toPrint = [
    this._name,
    (new Date).toJSON(),
    '[' + level + ']',
    msg].join(' ');

  switch (level) {
    case 'ERROR':
      console.error(toPrint);
      break;
    case 'WARN':
      console.warn(toPrint);
      break;
    default:
      console.log(toPrint);
      break;
  }
}

Logger.prototype.info   = function(msg) { this._print('INFO',   msg); }
Logger.prototype.debug  = function(msg) { this._print('DEBUG',  msg); }
Logger.prototype.trace  = function(msg) { this._print('TRACE',  msg); }
Logger.prototype.notice = function(msg) { this._print('NOTICE', msg); }
Logger.prototype.warn   = function(msg) { this._print('WARN',   msg); }
Logger.prototype.error  = function(msg) { this._print('ERROR',  msg); }

var Gmail = function() {
  this.inboxLink = null;

  if (!$)
    throw new Error('Zepto must be initialized first');
}

Gmail.prototype.threadId = function() {
  var location = String(document.location);
  return location.substr(location.lastIndexOf('/') + 1);
}

Gmail.prototype.threadSubject = function() {
  return this._canvas()
    .find('.hP')
    //.filter(':visible') XXX need to build the selector module in zepto
    .text();
}

Gmail.prototype.isThread = function() {
  return (this.threadId() !== '#inbox')
}

Gmail.prototype._originalUrl = function(id) {
  //XXX make sure we return the right URL
  // is http vs https, apps domain, etc
  return 'https://mail.google.com/mail/u/0/?ui=2&ik=50e71a47f3&view=om&th=' + id;
}

Gmail.prototype.loadOriginal = function(id, callback) {
  if (typeof(id) !== 'string')
    throw new TypeError('id (string) is required');

  $.get(this._originalUrl(id), function(data) {
    log.debug('original email [' + id + '] loaded');
    return callback(data);
  });
}

Gmail.prototype.createEvent = function(callback) {
  // just posts the threadID to the appropriate API endpoint

  if (!this.isThread())
    if (callback) return callback(false);

  var event = {
    user_email: this.emailAddress(),
    subject: this.threadSubject(),
    thread_id: this.threadId(),
    message_id: null,
    inbound: true,
    start_date: Date(),
    duration: 30,
    contact_email: 'notimplemented@example.com'
  }

  console.log(event);

  $.post(options.apiHost + '/api/events.json', {event:event}, function(data) {
    log.info('created event');
    if (callback)
      return callback(null)
  });

}

/*
// --- JSON Client
// just messin' around.

var Client = function(options) {
  if (typeof(options) !== 'object')
    throw new TypeError ('options (object) is required');

  this._url = options.url;
  this._pretty = options.pretty || false;
  this._timeout = options.timeout || 0;
  this._contentType = 'application/json';
  this._acceptsType = 'json'; // json, jsonp, xml, html or text

  this.contentWriters = {
    'application/json': function(v) {
      if (this.pretty) {
        return JSON.stringify(v, null, 2);
      } else {
        return JSON.stringify(v);
      }
    }
  }

}

Client.prototype._request = function(method, path, data, callback) {
  var self = this;
  var ajaxOptions = {
    type: 'GET',
    url: urlWithParams,
    data: data,
    contentType: self._contentType,
    dataType: self._acceptsType,
    timeout: self._timeout,
    headers: {},
    async: true,
    global: true,
    //content: window
  }

  ajaxOptions.success = function(data) {
    return callback(null, data);
  }

  ajaxOptions.error = function(xhr, type) {
    return callback(xhr, type);
  }

  $.ajax(ajaxOptions)

}

Client.prototype.serialize = function(data) {
  return this.contentWriters[this._contentType](data);
}

Client.prototype.get = function(path, callback) {
  this._request('GET', path, null, function(err, req, res, robj) {
    return callback(err, req, res);
  });
}

Client.prototype.post = function(path, obj, callback) {
  this._request('POST', path, obj, function(err, req, res, robj) {
    return callback(err, req, res, robj);
  });
}

Client.prototype.put = function(path, obj, callback) {
  this._request('PUT', path, obj, function(err, req, res, robj) {
    return callback(err, req, res, robj);
  });
}

Client.prototype.del = function(path, callback) {
  this._request('DELETE', path, null, function(err, req, res, robj) {
    return callback(err, req, res);
  });
}

*/

Gmail.prototype.postOriginal = function(id, callback) {
  if (typeof(id) !== 'string')
    throw new TypeError('id (string) is required');

  this.loadOriginal(id, function(email) {
    var encoded = window.btoa(email);
    log.debug('encoded result length: ' + encoded.length);
    var result = { base64: encoded }

    // Should probably be replaced with
    // some kind of API Client function
    // client.createEvent(data, callback);
    // client.updateEvent(id, data, callback);
    // client.deleteEvent(id, callback);
    // client.getEvent(id, callback);

    log.debug('POST /api/events.json');
    $.post(options.apiHost + '/api/events.json',
      JSON.stringify({base64: encoded}),
      function(data) {
        log.info('posted data');
        if (callback)
          return callback(null);
      }
    );

  });

}

Gmail.prototype.logo = function() {
  return this._canvas.find('[role=banner]');
}

Gmail.prototype.insertCss = function() {
  // do something
}

Gmail.prototype.currentView = function() {
  if (this._canvas().find('h1.ha').length > 0) {
    return 'conversation';
  } else {
    return 'thread';
  }
}

Gmail.prototype.banner = function() {
  return this._canvas().find(['role=banner']);
}

Gmail.prototype.emailAddress = function() {
  return document.title.split(/ - /)[1];
}

Gmail.prototype.numUnread = function() {
  var title, num;

  title = this.inboxUrl().title;
  num = /\((\d+)\)/.exec(title);
  return (num && num[1]) ? parseInt(num[1]) : 0;
}

Gmail.prototype._canvas = function() {
  return $(document.getElementById('canvas_frame').contentDocument)
}

Gmail.prototype._body = function() {
  return this._canvas()
           .find('body')
           .first();
}

Gmail.prototype.inboxUrl = function() {
  var element, body, inbox;

  body= this._body();
  element = body.find('a[href$="#inbox"][title^="Inbox"]');

  if (element.length > 0)
    inbox = element.first()[0];

  return inbox;

}

Gmail.prototype.messageBody = function(index) {
  var messages, body;

  messages = gmail._body().find('.ii.gt.adP');

  if (!index) var index = messages.length - 1;

  if (messages.length > 0) {
    body = $(messages[index])
      .find('div')
      .first();
  }

  return body;
}

Gmail.prototype.messageBodyText = function(index) {
  var body = this.messageBody(index);
  if (body)
    return body.text();
}

Gmail.prototype.messageBodyHtml = function(index) {
  var body = this.messageBody(index);
  if (body)
    return body.html();
}

Gmail.prototype.addActionButton = function(label, index) {

  if (typeof(label) !== 'string')
    throw new TypeError('label (string) is required');

  if (!index)
    index = 0;

  var style="-webkit-user-select: none;";
  var label = "Create Thread";
  var tooltip = "Create Thread";

  var toInject =
    '
' +
    '
' +
    '
' + label + '' +
    '

'

  this._canvas().find('.iH')
    .children()
    .first()
    .append(toInject);

}

Gmail.prototype.insertCss = function(csslink) {
  var css = $('<link rel="stylesheet" type="text/css">');
  css.attr('href', csslink);
  this._canvas()
    .find('head').first()
    .append(css);
}

Gmail.prototype.addDeveloperToolbar = function() {
  log.info('adding dev toolbar');
  var self = this;

  var template =
    [ '
'
    , '  ebb'
    , '  '
    , '    <button id="submit">postOriginal</button>'
    , '    <button id="debug">debug</button>'
    , '    <button id="create_event">CREATE EVENT</button>'
    , '  '
    , '</div'
    ].join('\n');

  var clickButton = function(selector, action) {
    self._body().find(selector).on('click', action)
  }

  this._body()
    .prepend(template);

  clickButton('#ebb #actions #submit', function() {
    id = gmail.threadId();
    self.postOriginal(id);
  });

  clickButton('#ebb #actions #create_event', function() {
    self.createEvent();
  })

  clickButton('#ebb #actions #submit', function() {
    id = gmail.threadId();
    self.postOriginal(id);
  })

  clickButton('#ebb #actions #debug', function() {
    log.debug('printing debug output');
    console.log('-------------------------------------------------');
    console.log('emailAddress: ' + self.emailAddress());
    console.log('numUnread: ' + self.numUnread());
    console.log('inboxUrl: ' + self.inboxUrl());
    console.log('threadId: ' + self.threadId());
    console.log('threadSubject: ' + self.threadSubject());
    console.log('-------------------------------------------------');
  });

}

// ----------------------------------------------------
// Main
// ----------------------------------------------------

var log = new Logger({name: options.name, level: options.logLevel});
var gmail = new Gmail();

log.info('loaded');

var main = function() {
  gmail.insertCss(options.cssFile);
  if (options.development) {
    gmail.addDeveloperToolbar();
  }

}

Zepto(function($) {
  log.info('zepto loaded');
  setTimeout(main, 3000); //XXX this needs to be more elegant
});
<commit_msg>Increase the accuracy of extracting the user email from gmail page<commit_after>/*

   ebb chrome extension

   TODO:

   * incorporate handlebars for easier templating
   * gmail selectors for from, date, content body, etc
   * figure out how to scan a message body for dates
   * better load_complete support for gmail (everything is async)
   * try and get messageid from within gmail

*/

// --- Configuration
var options = {
  name: 'ebb',
  development: true,
  logLevel: 'debug',
  cssLink: 'styles/ebb.css',
  apiHost: 'http://ebb-when.herokuapp.com'
}

// --- Libraries

var Logger = function(options) {
  if (typeof(options) !== 'object')
    throw new TypeError('options (object) is required');

  if (!options.name)
    throw new TypeError('options.name (string) is required');

  var logLevels = [
    'INFO',
    'DEBUG'
  ];

  this._name = options.name;
  this._level = options.level || 'INFO'

}

Logger.prototype.name = function() {
  return this._name;
}

Logger.prototype.level = function() {
  return this._level;
}

Logger.prototype._print = function(level, msg) {
  var toPrint = [
    this._name,
    (new Date).toJSON(),
    '[' + level + ']',
    msg].join(' ');

  switch (level) {
    case 'ERROR':
      console.error(toPrint);
      break;
    case 'WARN':
      console.warn(toPrint);
      break;
    default:
      console.log(toPrint);
      break;
  }
}

Logger.prototype.info   = function(msg) { this._print('INFO',   msg); }
Logger.prototype.debug  = function(msg) { this._print('DEBUG',  msg); }
Logger.prototype.trace  = function(msg) { this._print('TRACE',  msg); }
Logger.prototype.notice = function(msg) { this._print('NOTICE', msg); }
Logger.prototype.warn   = function(msg) { this._print('WARN',   msg); }
Logger.prototype.error  = function(msg) { this._print('ERROR',  msg); }

var Gmail = function() {
  this.inboxLink = null;

  if (!$)
    throw new Error('Zepto must be initialized first');
}

Gmail.prototype.threadId = function() {
  var location = String(document.location);
  return location.substr(location.lastIndexOf('/') + 1);
}

Gmail.prototype.threadSubject = function() {
  return this._canvas()
    .find('.hP')
    //.filter(':visible') XXX need to build the selector module in zepto
    .text();
}

Gmail.prototype.isThread = function() {
  return (this.threadId() !== '#inbox')
}

Gmail.prototype._originalUrl = function(id) {
  //XXX make sure we return the right URL
  // is http vs https, apps domain, etc
  return 'https://mail.google.com/mail/u/0/?ui=2&ik=50e71a47f3&view=om&th=' + id;
}

Gmail.prototype.loadOriginal = function(id, callback) {
  if (typeof(id) !== 'string')
    throw new TypeError('id (string) is required');

  $.get(this._originalUrl(id), function(data) {
    log.debug('original email [' + id + '] loaded');
    return callback(data);
  });
}

Gmail.prototype.createEvent = function(callback) {
  // just posts the threadID to the appropriate API endpoint

  if (!this.isThread())
    if (callback) return callback(false);

  var event = {
    user_email: this.emailAddress(),
    subject: this.threadSubject(),
    thread_id: this.threadId(),
    message_id: null,
    inbound: true,
    start_date: Date(),
    duration: 30,
    contact_email: 'notimplemented@example.com'
  }

  console.log(event);

  $.post(options.apiHost + '/api/events.json', {event:event}, function(data) {
    log.info('created event');
    if (callback)
      return callback(null)
  });

}

/*
// --- JSON Client
// just messin' around.

var Client = function(options) {
  if (typeof(options) !== 'object')
    throw new TypeError ('options (object) is required');

  this._url = options.url;
  this._pretty = options.pretty || false;
  this._timeout = options.timeout || 0;
  this._contentType = 'application/json';
  this._acceptsType = 'json'; // json, jsonp, xml, html or text

  this.contentWriters = {
    'application/json': function(v) {
      if (this.pretty) {
        return JSON.stringify(v, null, 2);
      } else {
        return JSON.stringify(v);
      }
    }
  }

}

Client.prototype._request = function(method, path, data, callback) {
  var self = this;
  var ajaxOptions = {
    type: 'GET',
    url: urlWithParams,
    data: data,
    contentType: self._contentType,
    dataType: self._acceptsType,
    timeout: self._timeout,
    headers: {},
    async: true,
    global: true,
    //content: window
  }

  ajaxOptions.success = function(data) {
    return callback(null, data);
  }

  ajaxOptions.error = function(xhr, type) {
    return callback(xhr, type);
  }

  $.ajax(ajaxOptions)

}

Client.prototype.serialize = function(data) {
  return this.contentWriters[this._contentType](data);
}

Client.prototype.get = function(path, callback) {
  this._request('GET', path, null, function(err, req, res, robj) {
    return callback(err, req, res);
  });
}

Client.prototype.post = function(path, obj, callback) {
  this._request('POST', path, obj, function(err, req, res, robj) {
    return callback(err, req, res, robj);
  });
}

Client.prototype.put = function(path, obj, callback) {
  this._request('PUT', path, obj, function(err, req, res, robj) {
    return callback(err, req, res, robj);
  });
}

Client.prototype.del = function(path, callback) {
  this._request('DELETE', path, null, function(err, req, res, robj) {
    return callback(err, req, res);
  });
}

*/

Gmail.prototype.postOriginal = function(id, callback) {
  if (typeof(id) !== 'string')
    throw new TypeError('id (string) is required');

  this.loadOriginal(id, function(email) {
    var encoded = window.btoa(email);
    log.debug('encoded result length: ' + encoded.length);
    var result = { base64: encoded }

    // Should probably be replaced with
    // some kind of API Client function
    // client.createEvent(data, callback);
    // client.updateEvent(id, data, callback);
    // client.deleteEvent(id, callback);
    // client.getEvent(id, callback);

    log.debug('POST /api/events.json');
    $.post(options.apiHost + '/api/events.json',
      JSON.stringify({base64: encoded}),
      function(data) {
        log.info('posted data');
        if (callback)
          return callback(null);
      }
    );

  });

}

Gmail.prototype.logo = function() {
  return this._canvas.find('[role=banner]');
}

Gmail.prototype.insertCss = function() {
  // do something
}

Gmail.prototype.currentView = function() {
  if (this._canvas().find('h1.ha').length > 0) {
    return 'conversation';
  } else {
    return 'thread';
  }
}

Gmail.prototype.banner = function() {
  return this._canvas().find(['role=banner']);
}

Gmail.prototype.emailAddress = function() {

  //['#guser nobr b','#gbmpc','.gbpc','#gbg6','#gbg4']

  var e = undefined;
  $('.gbpc .gbps2, #gbg6, #gbg4', this._canvas()).each(function(i, elements) {
    console.log($(elements).text());
    e = $(elements).text();
    if (e != undefined) {
      return false;
    }
  });

  return e; //document.title.split(/ - /)[1];
}

Gmail.prototype.numUnread = function() {
  var title, num;

  title = this.inboxUrl().title;
  num = /\((\d+)\)/.exec(title);
  return (num && num[1]) ? parseInt(num[1]) : 0;
}

Gmail.prototype._canvas = function() {
  return $(document.getElementById('canvas_frame').contentDocument)
}

Gmail.prototype._body = function() {
  return this._canvas()
           .find('body')
           .first();
}

Gmail.prototype.inboxUrl = function() {
  var element, body, inbox;

  body= this._body();
  element = body.find('a[href$="#inbox"][title^="Inbox"]');

  if (element.length > 0)
    inbox = element.first()[0];

  return inbox;

}

Gmail.prototype.messageBody = function(index) {
  var messages, body;

  messages = gmail._body().find('.ii.gt.adP');

  if (!index) var index = messages.length - 1;

  if (messages.length > 0) {
    body = $(messages[index])
      .find('div')
      .first();
  }

  return body;
}

Gmail.prototype.messageBodyText = function(index) {
  var body = this.messageBody(index);
  if (body)
    return body.text();
}

Gmail.prototype.messageBodyHtml = function(index) {
  var body = this.messageBody(index);
  if (body)
    return body.html();
}

Gmail.prototype.addActionButton = function(label, index) {

  if (typeof(label) !== 'string')
    throw new TypeError('label (string) is required');

  if (!index)
    index = 0;

  var style="-webkit-user-select: none;";
  var label = "Create Thread";
  var tooltip = "Create Thread";

  var toInject =
    '
' +
    '
' +
    '
' + label + '' +
    '

'

  this._canvas().find('.iH')
    .children()
    .first()
    .append(toInject);

}

Gmail.prototype.insertCss = function(csslink) {
  var css = $('<link rel="stylesheet" type="text/css">');
  css.attr('href', csslink);
  this._canvas()
    .find('head').first()
    .append(css);
}

Gmail.prototype.addDeveloperToolbar = function() {
  log.info('adding dev toolbar');
  var self = this;

  var template =
    [ '
'
    , '  ebb'
    , '  '
    , '    <button id="submit">postOriginal</button>'
    , '    <button id="debug">debug</button>'
    , '    <button id="create_event">CREATE EVENT</button>'
    , '  '
    , '</div'
    ].join('\n');

  var clickButton = function(selector, action) {
    self._body().find(selector).on('click', action)
  }

  this._body()
    .prepend(template);

  clickButton('#ebb #actions #submit', function() {
    id = gmail.threadId();
    self.postOriginal(id);
  });

  clickButton('#ebb #actions #create_event', function() {
    self.createEvent();
  })

  clickButton('#ebb #actions #submit', function() {
    id = gmail.threadId();
    self.postOriginal(id);
  })

  clickButton('#ebb #actions #debug', function() {
    log.debug('printing debug output');
    console.log('-------------------------------------------------');
    console.log('emailAddress: ' + self.emailAddress());
    console.log('numUnread: ' + self.numUnread());
    console.log('inboxUrl: ' + self.inboxUrl());
    console.log('threadId: ' + self.threadId());
    console.log('threadSubject: ' + self.threadSubject());
    console.log('-------------------------------------------------');
  });

}

// ----------------------------------------------------
// Main
// ----------------------------------------------------

var log = new Logger({name: options.name, level: options.logLevel});
var gmail = new Gmail();

log.info('loaded');

var main = function() {
  gmail.insertCss(options.cssFile);
  if (options.development) {
    gmail.addDeveloperToolbar();
  }

}

Zepto(function($) {
  log.info('zepto loaded');
  setTimeout(main, 3000); //XXX this needs to be more elegant
});
<|endoftext|>


<commit_before>//app.js
const defaultTime = {
  defaultWorkTime: 25,
  defaultRestTime: 5
}

App({
  onLaunch: function () {
    //加载主题
    let objects = {
      tableID: 1323,
      userId: this.getUserId()
    };
    wx.BaaS.getRecordList(objects).then((res) => {

      that.setData({

      })
    }, (err) => {
      // err
      console.dir(err);
    });

    let workTime = wx.getStorageSync('workTime')
    let restTime = wx.getStorageSync('restTime')
    if (!workTime) {
      wx.setStorage({
        key: 'workTime',
        data: defaultTime.defaultWorkTime
      })
    }
    if (!restTime) {
      wx.setStorage({
        key: 'restTime',
        data: defaultTime.defaultRestTime
      })
    }

    let that = this

    wx.getSystemInfo({
      complete(res) {
        if (res.errMsg == 'getSystemInfo:ok') {
          let systemInfo = {
            model: res.model,
            language: res.language,
            version: res.version,
            system: res.system,
            wH: res.windowHeight,
            wW: res.windowWidth
          }
          that.systemInfo = systemInfo
        }

      }
    })

    // 引入 BaaS SDK
    require('./utils/sdk-v1.0.11.js')

    // 从 BaaS 后台获取 ClientID
    let clientId = 'e565b5fcd30ce9a1271e'

    let userId = this.getUserId();
    wx.BaaS.init(clientId)
    if (!userId) {
      wx.BaaS.login()
        .then(res => {
          console.log('BaaS is logined!')
        }).catch(err => {
          console.dir(err)
        })
    }

  },
  getUserId() {
    if (this.userId) {
      return this.userId
    }

    this.userId = wx.BaaS.storage.get('uid')
    return this.userId
  },

  getUserInfo() {

    if (this.userInfo) {
      return this.userInfo
    }

    this.userInfo = wx.BaaS.storage.get('userinfo')
    return this.userInfo
  }

})
<commit_msg>fix:更新获取主题数据代码位置<commit_after>//app.js
const defaultTime = {
  defaultWorkTime: 25,
  defaultRestTime: 5
}

App({
  onLaunch: function () {

    let workTime = wx.getStorageSync('workTime')
    let restTime = wx.getStorageSync('restTime')
    if (!workTime) {
      wx.setStorage({
        key: 'workTime',
        data: defaultTime.defaultWorkTime
      })
    }
    if (!restTime) {
      wx.setStorage({
        key: 'restTime',
        data: defaultTime.defaultRestTime
      })
    }

    let that = this

    wx.getSystemInfo({
      complete(res) {
        if (res.errMsg == 'getSystemInfo:ok') {
          let systemInfo = {
            model: res.model,
            language: res.language,
            version: res.version,
            system: res.system,
            wH: res.windowHeight,
            wW: res.windowWidth
          }
          that.systemInfo = systemInfo
        }

      }
    })

    // 引入 BaaS SDK
    require('./utils/sdk-v1.0.11.js')

    // 从 BaaS 后台获取 ClientID
    let clientId = 'e565b5fcd30ce9a1271e'

    let userId = this.getUserId();
    wx.BaaS.init(clientId)
    if (!userId) {
      wx.BaaS.login()
        .then(res => {
          console.log('BaaS is logined!')
        }).catch(err => {
          console.dir(err)
        })
    }

    //加载主题
    let objects = {
      tableID: 1323,
      userId: this.getUserId()
    };
    wx.BaaS.getRecordList(objects).then((res) => {

      that.setData({

      })
    }, (err) => {
      // err
      console.dir(err);
    });

  },

  getUserId() {
    if (this.userId) {
      return this.userId
    }

    this.userId = wx.BaaS.storage.get('uid')
    return this.userId
  },

  getUserInfo() {

    if (this.userInfo) {
      return this.userInfo
    }

    this.userInfo = wx.BaaS.storage.get('userinfo')
    return this.userInfo
  }

})
<|endoftext|>


<commit_before>var socket = require('socket.io-client')('http://qssub.cloudapp.net:8080');

var pkct = 0;
var processStart;  // epoch in ms
var processEnd;    // epoch in ms
var fullData = {}; // 1-indexed
var cnns = 0;
var dscn = 0;
var rcns = 0;

console.time("quake");

socket.on("connect", function() {
	++cnns;
	console.log(process.pid + " socket connected");
}), socket.on("message", function(t) {
	var e = JSON.parse(t);

	if ( !e.data ){
		return;
	}

	pkct++;

	if (!processStart) {
		processStart = e.starttime;
	}

	processEnd = e.endtime;

	var msgl = t.toString().length;     // in bytes
	var msgd = e.endtime - e.starttime; // in ms
	var bptd = msgl / msgd;             // in bytes/ms
	fullData[pkct] = { msgl: msgl, msgd: msgd, bptd: bptd };
}), socket.on("disconnect", function() {
	++dscn;
	console.log(process.pid + " socket disconnected");
}), socket.on("reconnect", function() {
	++rcns;
	console.log(process.pid + " socket reconnected");
});

process.on('SIGINT', function() {
	console.log("Caught interrupt signal");
	wrapup();
	process.exit();
});

function wrapup() {
	if (!pkct || !processEnd || !processStart) {
		return;
	}

	var rate = pkct/(processEnd-processStart)*1e5;

	console.log("Packets      " + pkct);
	console.log("Rate (pk/s)  " + rate);
	console.log("Duration (s) " + (processEnd-processStart)/1e5);
	console.log("Connects     " + cnns);
	console.log("Reconnects   " + rcns);
	console.log("Disconnects  " + dscn);

	console.timeEnd("quake");
}
<commit_msg>Differentiating process time deltas from packet time deltas<commit_after>var socket = require('socket.io-client')('http://qssub.cloudapp.net:8080');

var pkct = 0;
var packetStart;  // epoch in ms
var packetEnd = 0;    // epoch in ms
var fullData = {}; // 1-indexed
var cnns = 0;
var dscn = 0;
var rcns = 0;

console.time("quake");

socket.on("connect", function() {
	++cnns;
	console.log(process.pid + " socket connected");

}), socket.on("message", function(t) {
	var e = JSON.parse(t);

	if (!e.data){
		return;
	}

	pkct++;

	if (!packetStart) {
		packetStart = e.starttime;
	}

	if ( e.endtime > packetEnd ) {
		packetEnd = e.endtime;
	}
/*
	var msgl = t.toString().length;     // in bytes
	var msgd = e.endtime - e.starttime; // in ms
	var bptd = msgl / msgd;             // in bytes/ms

	fullData[pkct] = { msgl: msgl, msgd: msgd, bptd: bptd };
*/

}), socket.on("disconnect", function() {
	++dscn;
	console.log(process.pid + " socket disconnected");

}), socket.on("reconnect", function() {
	++rcns;
	console.log(process.pid + " socket reconnected");
});

process.on('SIGINT', function() {
	console.log("Caught interrupt signal");
	wrapup();
	process.exit();
});

function wrapup() {
	if (!pkct || !packetEnd || !packetStart) {
		return;
	}

	var rate = pkct/((packetEnd-packetStart)/1e5);

	console.log("Packets      " + pkct);
	console.log("Rate         " + rate);
	console.log("Duration     " + (packetEnd-packetStart)/1e5);
	console.log("Connects     " + cnns);
	console.log("Reconnects   " + rcns);
	console.log("Disconnects  " + dscn);

	console.log("Start packet " + packetStart);
	console.log("Final packet " + packetEnd);

	console.timeEnd("quake");
}
<|endoftext|>


<commit_before>'use strict'

const io = require('socket.io-client')
const Config = require('./config.js')
const Rooms  = require('./rooms.js')
const Input = require('./input.js')
const Colors = require('./color.js')

const socket = io.connect(Config.serverURL)
let username = 'anonymous'

const userConfig = Input.setName()
    .then((uname) => {
        username = uname
        return Rooms.getRooms()
    })
    .then((chatRooms) => {
        console.log('Available rooms:')
        if (chatRooms.length) {
            chatRooms
                .forEach(room => console.log(`${room.name}: ${room.size} online`))
        } else {
            console.log('No current chat rooms, create your own.')
        }
        return Input.setRoom()
    })
    .catch((err) => {
        console.log('Error getting rooms: ', err)
    })

socket.on('connect', (data) => {
    userConfig
        .then((room) => {
            socket.emit('create', room)
            console.log(`Joined room: ${room}`)

            Input.setMessage(messageHandler)
            Input.setPrompt()
        })
        .catch((err) => {
            console.log('Error connecting to room: ', err)
        })
})

socket.on('chat', (data) => {
    const date = new Date(data.date)
    const hour = date.getHours()
    const min = date.getMinutes()

    Input.clearLine()
    if (min < 10) {
        process.stdout.write(Colors.cyan +`${hour}:0${min} : ` + Colors.reset + Colors.yellowBgBlackLt +`${data.name}` + Colors.reset +`\n`)
    } else {
        process.stdout.write(Colors.cyan +`${hour}:${min} : ` + Colors.reset + Colors.yellowBgBlackLt +`${data.name}` + Colors.reset +`\n`)
    }
    process.stdout.write(Colors.reset + `- ${data.message}` + `\n`)
    Input.setPrompt()
})

socket.on('invalid', (err) => {
    console.log('Error invalid: ', err)
})

function messageHandler(message) {
    if (message === ':q') {
        process.exit()
    }
    socket.emit('chat', {
        name: username,
        date: new Date(),
        message: message
    })
}
<commit_msg>started using ansi-color to make code cleaner<commit_after>'use strict'

const io = require('socket.io-client')
const Config = require('./config.js')
const Rooms  = require('./rooms.js')
const Input = require('./input.js')
//const Colors = require('./color.js')
const color = require('ansi-color').set

const socket = io.connect(Config.serverURL)
let username = 'anonymous'

const userConfig = Input.setName()
    .then((uname) => {
        username = uname
        return Rooms.getRooms()
    })
    .then((chatRooms) => {
        console.log('Available rooms:')
        if (chatRooms.length) {
            chatRooms
                .forEach(room => console.log(`${room.name}: ${room.size} online`))
        } else {
            console.log('No current chat rooms, create your own.')
        }
        return Input.setRoom()
    })
    .catch((err) => {
        console.log('Error getting rooms: ', err)
    })

socket.on('connect', (data) => {
    userConfig
        .then((room) => {
            socket.emit('create', room)
            console.log(`Joined room: ${room}`)

            Input.setMessage(messageHandler)
            Input.setPrompt()
        })
        .catch((err) => {
            console.log('Error connecting to room: ', err)
        })
})

socket.on('chat', (data) => {
    const date = new Date(data.date)
    const hour = date.getHours()
    const min = date.getMinutes()

    Input.clearLine()
    if (min < 10) {
        process.stdout.write(color(`${hour}:0${min} : `, 'cyan'))
		process.stdout.write(color(`${data.name}` + `\n`, 'yellow'))
    } else {
        process.stdout.write(color(`${hour}:${min} : `, 'green'))
		procces.stdout.write(color(`${data.name}` + `\n`, 'yellow'))
    }
	//TODO: recive color from server based on who sent the message
    process.stdout.write(color(`- ${data.message}` + `\n`, 'blue+bold' ))
    Input.setPrompt()
})

socket.on('invalid', (err) => {
    console.log('Error invalid: ', err)
})

function messageHandler(message) {
    if (message === ':q') {
        process.exit()
    }
    socket.emit('chat', {
        name: username,
        date: new Date(),
        message: message
    })
}
<|endoftext|>


<commit_before>var blocJobs = angular.module('blocJobs', ["ui.router", "firebase", "jcs-autoValidate"]); //"jcs-autoValidate"

blocJobs.run(function (defaultErrorMessageResolver) {
    defaultErrorMessageResolver.getErrorMessages().then(function (errorMessages) {
        errorMessages['jobTitle'] = 'Job title can only contain numbers and letters';
        errorMessages['companyName'] = 'Company name can only contain numbers and letters';
        errorMessages['jobDescription'] = 'Please enter a URL, or description of job';
        errorMessages['postalCode'] = 'Please enter a valid postal code';
    })
});

blocJobs.config(function($stateProvider, $urlRouterProvider){

    // For any unmatched url, send to /route1
    $urlRouterProvider.otherwise("/")

    $stateProvider
    .state('landing', {
         url: '/',
         controller: 'mainCtrl',
         templateUrl: '/templates/landing.html'
     })
    .state('job-post', {
        url: "/job-post",
        controller: 'jobPostCtrl',
        templateUrl: "/templates/job-post.html"
    })
    .state('postings', {
        url: "/postings",
        controller: 'postingsCtrl',
        templateUrl: "/templates/postings.html"
    })
})

// RE-USABLE FACTORY THAT GENERATES THE $firebaseAuth INSTANCE
blocJobs.factory("Auth", function($firebaseAuth) {
  var ref = new Firebase("https://keodo-todo-list.firebaseio.com");
  return $firebaseAuth(ref);
});

// navi-menu DIRECTIVE USED FOR EACH TEMPLATE
blocJobs.directive("naviMenu", function() {
    return {
        template: '

BLOC

Frontend Web Development

Roadmaps

Page 1-1

Page 1-2

Page 1-3

Messages

Schedule

 Account

Log inLog out

'
    }
});<commit_msg>updated app.js<commit_after>var blocJobs = angular.module('blocJobs', ["ui.router", "firebase", "jcs-autoValidate"]); //"jcs-autoValidate"

blocJobs.run(function (defaultErrorMessageResolver) {
    defaultErrorMessageResolver.getErrorMessages().then(function (errorMessages) {
        errorMessages['jobTitle'] = 'Job title can only contain numbers and letters';
        errorMessages['companyName'] = 'Company name can only contain numbers and letters';
        errorMessages['jobDescription'] = 'Please enter a URL, or description of job';
        errorMessages['postalCode'] = 'Please enter a valid postal code';
    })
});

blocJobs.config(function($stateProvider, $urlRouterProvider){

    // For any unmatched url, send to /route1
    $urlRouterProvider.otherwise("/")

    $stateProvider
    .state('landing', {
         url: '/',
         controller: 'mainCtrl',
         templateUrl: 'landing.html'
     })
    .state('job-post', {
        url: "/job-post",
        controller: 'jobPostCtrl',
        templateUrl: "job-post.html"
    })
    .state('postings', {
        url: "/postings",
        controller: 'postingsCtrl',
        templateUrl: "postings.html"
    })
})

// RE-USABLE FACTORY THAT GENERATES THE $firebaseAuth INSTANCE
blocJobs.factory("Auth", function($firebaseAuth) {
  var ref = new Firebase("https://keodo-todo-list.firebaseio.com");
  return $firebaseAuth(ref);
});

// navi-menu DIRECTIVE USED FOR EACH TEMPLATE
blocJobs.directive("naviMenu", function() {
    return {
        template: '

BLOC

Frontend Web Development

Roadmaps

Page 1-1

Page 1-2

Page 1-3

Messages

Schedule

 Account

Log inLog out

'
    }
});<|endoftext|>


<commit_before>/**
 * Module dependencies.
 */
const express = require('express');
const compression = require('compression');
const session = require('express-session');
const bodyParser = require('body-parser');
const logger = require('morgan');
const chalk = require('chalk');
const errorHandler = require('errorhandler');
const lusca = require('lusca');
const dotenv = require('dotenv');
const MongoStore = require('connect-mongo')(session);
const flash = require('express-flash');
const path = require('path');
const mongoose = require('mongoose');
const passport = require('passport');
const expressValidator = require('express-validator');
const expressStatusMonitor = require('express-status-monitor');
const sass = require('node-sass-middleware');
const multer = require('multer');

const upload = multer({ dest: path.join(__dirname, 'uploads') });

/**
 * Load environment variables from .env file, where API keys and passwords are configured.
 */
dotenv.load({ path: '.env.example' });

/**
 * Controllers (route handlers).
 */
const homeController = require('./controllers/home');
const userController = require('./controllers/user');
const apiController = require('./controllers/api');
const contactController = require('./controllers/contact');

/**
 * API keys and Passport configuration.
 */
const passportConfig = require('./config/passport');

/**
 * Create Express server.
 */
const app = express();

/**
 * Connect to MongoDB.
 */
mongoose.Promise = global.Promise;
mongoose.connect(process.env.MONGODB_URI || process.env.MONGOLAB_URI);
mongoose.connection.on('error', () => {
  console.log('%s MongoDB connection error. Please make sure MongoDB is running.', chalk.red('✗'));
  process.exit();
});

/**
 * Express configuration.
 */
app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(expressStatusMonitor());
app.use(compression());
app.use(sass({
  src: path.join(__dirname, 'public'),
  dest: path.join(__dirname, 'public')
}));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(expressValidator());
app.use(session({
  resave: true,
  saveUninitialized: true,
  secret: process.env.SESSION_SECRET,
  store: new MongoStore({
    url: process.env.MONGODB_URI || process.env.MONGOLAB_URI,
    autoReconnect: true
  })
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
app.use((req, res, next) => {
  if (req.path === '/api/upload') {
    next();
  } else {
    lusca.csrf()(req, res, next);
  }
});
app.use(lusca.xframe('SAMEORIGIN'));
app.use(lusca.xssProtection(true));
app.use((req, res, next) => {
  res.locals.user = req.user;
  next();
});
app.use((req, res, next) => {
  // After successful login, redirect back to the intended page
  if (!req.user &&
      req.path !== '/login' &&
      req.path !== '/signup' &&
      !req.path.match(/^\/auth/) &&
      !req.path.match(/\./)) {
    req.session.returnTo = req.path;
  } else if (req.user &&
      req.path == '/account') {
    req.session.returnTo = req.path;
  }
  next();
});
app.use(express.static(path.join(__dirname, 'public'), { maxAge: 31557600000 }));

/**
 * Primary app routes.
 */
app.get('/', homeController.index);
app.get('/login', userController.getLogin);
app.post('/login', userController.postLogin);
app.get('/logout', userController.logout);
app.get('/forgot', userController.getForgot);
app.post('/forgot', userController.postForgot);
app.get('/reset/:token', userController.getReset);
app.post('/reset/:token', userController.postReset);
app.get('/signup', userController.getSignup);
app.post('/signup', userController.postSignup);
app.get('/contact', contactController.getContact);
app.post('/contact', contactController.postContact);
app.get('/account', passportConfig.isAuthenticated, userController.getAccount);
app.post('/account/profile', passportConfig.isAuthenticated, userController.postUpdateProfile);
app.post('/account/password', passportConfig.isAuthenticated, userController.postUpdatePassword);
app.post('/account/delete', passportConfig.isAuthenticated, userController.postDeleteAccount);
app.get('/account/unlink/:provider', passportConfig.isAuthenticated, userController.getOauthUnlink);

/**
 * API examples routes.
 */
app.get('/api', apiController.getApi);
app.get('/api/instagram', passportConfig.isAuthenticated, passportConfig.isAuthorized, apiController.getInstagram);

/**
 * OAuth authentication routes. (Sign in)
 */
app.get('/auth/instagram', passport.authenticate('instagram'));
app.get('/auth/instagram/callback', passport.authenticate('instagram', { failureRedirect: '/login' }), (req, res) => {
  res.redirect(req.session.returnTo || '/');
});

/**
 * Error Handler.
 */
app.use(errorHandler());

/**
 * Start Express server.
 */
app.listen(app.get('port'), () => {
  console.log('%s App is running at http://localhost:%d in %s mode', chalk.green('✓'), app.get('port'), app.get('env'));

  console.log('  Press CTRL-C to stop\n');
});

module.exports = app;
<commit_msg>Use .env instead of .env.example<commit_after>/**
 * Module dependencies.
 */
const express = require('express');
const compression = require('compression');
const session = require('express-session');
const bodyParser = require('body-parser');
const logger = require('morgan');
const chalk = require('chalk');
const errorHandler = require('errorhandler');
const lusca = require('lusca');
const dotenv = require('dotenv');
const MongoStore = require('connect-mongo')(session);
const flash = require('express-flash');
const path = require('path');
const mongoose = require('mongoose');
const passport = require('passport');
const expressValidator = require('express-validator');
const expressStatusMonitor = require('express-status-monitor');
const sass = require('node-sass-middleware');
const multer = require('multer');

const upload = multer({ dest: path.join(__dirname, 'uploads') });

/**
 * Load environment variables from .env file, where API keys and passwords are configured.
 */
dotenv.load({ path: '.env' });

/**
 * Controllers (route handlers).
 */
const homeController = require('./controllers/home');
const userController = require('./controllers/user');
const apiController = require('./controllers/api');
const contactController = require('./controllers/contact');

/**
 * API keys and Passport configuration.
 */
const passportConfig = require('./config/passport');

/**
 * Create Express server.
 */
const app = express();

/**
 * Connect to MongoDB.
 */
mongoose.Promise = global.Promise;
mongoose.connect(process.env.MONGODB_URI || process.env.MONGOLAB_URI);
mongoose.connection.on('error', () => {
  console.log('%s MongoDB connection error. Please make sure MongoDB is running.', chalk.red('✗'));
  process.exit();
});

/**
 * Express configuration.
 */
app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(expressStatusMonitor());
app.use(compression());
app.use(sass({
  src: path.join(__dirname, 'public'),
  dest: path.join(__dirname, 'public')
}));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(expressValidator());
app.use(session({
  resave: true,
  saveUninitialized: true,
  secret: process.env.SESSION_SECRET,
  store: new MongoStore({
    url: process.env.MONGODB_URI || process.env.MONGOLAB_URI,
    autoReconnect: true
  })
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
app.use((req, res, next) => {
  if (req.path === '/api/upload') {
    next();
  } else {
    lusca.csrf()(req, res, next);
  }
});
app.use(lusca.xframe('SAMEORIGIN'));
app.use(lusca.xssProtection(true));
app.use((req, res, next) => {
  res.locals.user = req.user;
  next();
});
app.use((req, res, next) => {
  // After successful login, redirect back to the intended page
  if (!req.user &&
      req.path !== '/login' &&
      req.path !== '/signup' &&
      !req.path.match(/^\/auth/) &&
      !req.path.match(/\./)) {
    req.session.returnTo = req.path;
  } else if (req.user &&
      req.path == '/account') {
    req.session.returnTo = req.path;
  }
  next();
});
app.use(express.static(path.join(__dirname, 'public'), { maxAge: 31557600000 }));

/**
 * Primary app routes.
 */
app.get('/', homeController.index);
app.get('/login', userController.getLogin);
app.post('/login', userController.postLogin);
app.get('/logout', userController.logout);
app.get('/forgot', userController.getForgot);
app.post('/forgot', userController.postForgot);
app.get('/reset/:token', userController.getReset);
app.post('/reset/:token', userController.postReset);
app.get('/signup', userController.getSignup);
app.post('/signup', userController.postSignup);
app.get('/contact', contactController.getContact);
app.post('/contact', contactController.postContact);
app.get('/account', passportConfig.isAuthenticated, userController.getAccount);
app.post('/account/profile', passportConfig.isAuthenticated, userController.postUpdateProfile);
app.post('/account/password', passportConfig.isAuthenticated, userController.postUpdatePassword);
app.post('/account/delete', passportConfig.isAuthenticated, userController.postDeleteAccount);
app.get('/account/unlink/:provider', passportConfig.isAuthenticated, userController.getOauthUnlink);

/**
 * API examples routes.
 */
app.get('/api', apiController.getApi);
app.get('/api/instagram', passportConfig.isAuthenticated, passportConfig.isAuthorized, apiController.getInstagram);

/**
 * OAuth authentication routes. (Sign in)
 */
app.get('/auth/instagram', passport.authenticate('instagram'));
app.get('/auth/instagram/callback', passport.authenticate('instagram', { failureRedirect: '/login' }), (req, res) => {
  res.redirect(req.session.returnTo || '/');
});

/**
 * Error Handler.
 */
app.use(errorHandler());

/**
 * Start Express server.
 */
app.listen(app.get('port'), () => {
  console.log('%s App is running at http://localhost:%d in %s mode', chalk.green('✓'), app.get('port'), app.get('env'));

  console.log('  Press CTRL-C to stop\n');
});

module.exports = app;
<|endoftext|>


<commit_before>var fs = require('fs');
var express = require('express');
var path = require('path');
var nunjucks = require('nunjucks');
var marked = require('marked');
var _ = require('underscore');

var TransformOMatic = require('./lib/transform');

var app = express();

//CORS middleware
var CORSSupport = function(req, res, next) {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
  res.header('Access-Control-Allow-Headers', 'Content-Type');
  // intercept OPTIONS method
  if ('OPTIONS' == req.method) {
    res.send(200);
  }
  else {
    next();
  }
};

var chromeSpaceReplace = function(req, res, next) {
  var agent = req.headers['user-agent'] || '';
  if (agent.indexOf('Chrome') !== -1 && req.url.indexOf('%20') !== -1) {
    // replace %20s with nbsps
    var url = req.url.replace(/%20/g, ' ');
    res.redirect(url);
    return;
  }

  next();
};

app.configure(function(){
  app.set('port', process.env.PORT || 5000);
  app.set('views', __dirname + '/templates');
  app.use(express.logger('dev'));
  app.use(chromeSpaceReplace);
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(CORSSupport);
  app.use(express.static(path.join(__dirname, 'public')));
});

var env = new nunjucks.Environment(new nunjucks.FileSystemLoader('templates'));
env.express(app);

function getMarkdownContent(filepath, cb) {
  fs.readFile(filepath, 'utf8', function(err, text) {
    if (err) {
      cb(err, null);
    } else {
      cb(null, marked(text, {gfm: false}));
    }
  });
}

function datapipe(path, query, res) {
  // remove leading&trailing spaces&slashes
  var transformStr = path.replace(/(\/|\s)+$/g, '');
  // replace nbsps with spaces
  transformStr = transformStr.replace(/ /g, ' ');

  // rewrite the transform string in the form required
  transformStr = TransformOMatic.rejig(transformStr);

  var transformers = TransformOMatic.pipeline(transformStr, query, res);

  if (_.last(transformers).contentType) {
    res.setHeader("Content-Type", _.last(transformers).contentType());
  } else {
    // default to plain text
    res.setHeader("Content-Type", "text/plain; charset=utf-8");
  }

  TransformOMatic.transform(res, transformers, query.url);
}

// this route runs everything through a pipeline.
// it never serves docs pages.
app.get(/\/exec\/(.*)?/, function(req, res) {
  path = req.params[0] || '';
  if (!req.query.url) {
    var errStr = 'A URL is required.';
    console.log(errStr);
    res.send(500, errStr);
    res.end();
    return;
  }
  datapipe(path, req.query, res);
});

app.get(/\/interactive(\/.*)?/, function(req, res) {
  var pipeline = '';
  queryStr = _.map(req.query, function(v, k) {
    return k + '=' + v;
  }).join('&');

  if (req.params[0] !== undefined) {
    pipeline = req.params[0] + '?' + queryStr;
  } else if (queryStr !== '') {
    // default pipeline: /csv/head
    pipeline = '/csv/head?' + queryStr;
  }

  res.render('interactive.html', {
    pipeline: pipeline,
  });
});

app.get('/*', function(req, res) {
  var mdFilename;
  var path = req.params[0];

  if (!req.query.url) {
    // if there's no url parameter,
    // attempt to serve a docs page
    var page = path.split('/')[0];
    if (page === '') {
      mdFilename = 'docs/index.md';
    } else {
      mdFilename = 'docs/op-' + page + '.md';
    }
    getMarkdownContent(mdFilename, function(err, content) {
      if (err) {
        console.log(err);
        res.send(404, 'Page not found: ' + req.params[0]);
      } else {
        res.render('docs.html', {
          content: content
        });
      }
    });
  } else {
    datapipe(path, req.query, res);
  }
});

app.listen(app.get('port'), function() {
  console.log("Listening on " + app.get('port'));
});

exports.app = app;
<commit_msg>[#87,#100][s]: disable space replacer in chrome as leads to breakage.<commit_after>var fs = require('fs');
var express = require('express');
var path = require('path');
var nunjucks = require('nunjucks');
var marked = require('marked');
var _ = require('underscore');

var TransformOMatic = require('./lib/transform');

var app = express();

//CORS middleware
var CORSSupport = function(req, res, next) {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
  res.header('Access-Control-Allow-Headers', 'Content-Type');
  // intercept OPTIONS method
  if ('OPTIONS' == req.method) {
    res.send(200);
  }
  else {
    next();
  }
};

var chromeSpaceReplace = function(req, res, next) {
  var agent = req.headers['user-agent'] || '';
  if (agent.indexOf('Chrome') !== -1 && req.url.indexOf('%20') !== -1) {
    // replace %20s with nbsps
    var url = req.url.replace(/%20/g, ' ');
    res.redirect(url);
    return;
  }

  next();
};

app.configure(function(){
  app.set('port', process.env.PORT || 5000);
  app.set('views', __dirname + '/templates');
  app.use(express.logger('dev'));
  // app.use(chromeSpaceReplace);
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(CORSSupport);
  app.use(express.static(path.join(__dirname, 'public')));
});

var env = new nunjucks.Environment(new nunjucks.FileSystemLoader('templates'));
env.express(app);

function getMarkdownContent(filepath, cb) {
  fs.readFile(filepath, 'utf8', function(err, text) {
    if (err) {
      cb(err, null);
    } else {
      cb(null, marked(text, {gfm: false}));
    }
  });
}

function datapipe(path, query, res) {
  // remove leading&trailing spaces&slashes
  var transformStr = path.replace(/(\/|\s)+$/g, '');
  // replace nbsps with spaces
  transformStr = transformStr.replace(/ /g, ' ');

  // rewrite the transform string in the form required
  transformStr = TransformOMatic.rejig(transformStr);

  var transformers = TransformOMatic.pipeline(transformStr, query, res);

  if (_.last(transformers).contentType) {
    res.setHeader("Content-Type", _.last(transformers).contentType());
  } else {
    // default to plain text
    res.setHeader("Content-Type", "text/plain; charset=utf-8");
  }

  TransformOMatic.transform(res, transformers, query.url);
}

// this route runs everything through a pipeline.
// it never serves docs pages.
app.get(/\/exec\/(.*)?/, function(req, res) {
  path = req.params[0] || '';
  if (!req.query.url) {
    var errStr = 'A URL is required.';
    console.log(errStr);
    res.send(500, errStr);
    res.end();
    return;
  }
  datapipe(path, req.query, res);
});

app.get(/\/interactive(\/.*)?/, function(req, res) {
  var pipeline = '';
  queryStr = _.map(req.query, function(v, k) {
    return k + '=' + v;
  }).join('&');

  if (req.params[0] !== undefined) {
    pipeline = req.params[0] + '?' + queryStr;
  } else if (queryStr !== '') {
    // default pipeline: /csv/head
    pipeline = '/csv/head?' + queryStr;
  }

  res.render('interactive.html', {
    pipeline: pipeline,
  });
});

app.get('/*', function(req, res) {
  var mdFilename;
  var path = req.params[0];

  if (!req.query.url) {
    // if there's no url parameter,
    // attempt to serve a docs page
    var page = path.split('/')[0];
    if (page === '') {
      mdFilename = 'docs/index.md';
    } else {
      mdFilename = 'docs/op-' + page + '.md';
    }
    getMarkdownContent(mdFilename, function(err, content) {
      if (err) {
        console.log(err);
        res.send(404, 'Page not found: ' + req.params[0]);
      } else {
        res.render('docs.html', {
          content: content
        });
      }
    });
  } else {
    datapipe(path, req.query, res);
  }
});

app.listen(app.get('port'), function() {
  console.log("Listening on " + app.get('port'));
});

exports.app = app;
<|endoftext|>