<commit_before>/** @jsx React.DOM */
var DataCalculator = React.createClass({
    getInitialState: function() {
        return {
            usages: [],
            plans: [],
            tableShown: false
        };
    },
    loadPlansFromServer: function() {
        $.ajax({
            url: this.props.plansUrl,
            dataType: 'json',
            success: function(plans) {
                this.state.plans = plans;
                this.setState(this.state);
            }.bind(this),
            error: function(xhr, status, err) {
                console.error(this.props.url, status, err.toString());
            }.bind(this)
        });
    },
    handleDataEntered: function(usages) {
        var _this = this;

        this.state.usages = usages;
        this.setState(this.state);

        // Set the timeout so that react has a chance to build the dom (especially the first time)
        // Before we attempt to slide the result in
        setTimeout(function(){
            $(_this.refs.dataTable.getDOMNode()).slideDown();
            var tableDiv = $(_this.refs.dataTable.getDOMNode())
            $("body").animate({scrollTop: tableDiv.position().top});
            _this.state.tableShown = true;
            _this.setState(this.state);
        },10);
    },
    componentDidMount: function() {
        this.loadPlansFromServer();
    },
    render: function () {
        tableStyles = {};
        if (!this.state.tableShown) {
            tableStyles['display'] = "none";
        }

        return (

                <DataEntryForm onDataEntered={this.handleDataEntered} />
                <DataTable styles={tableStyles} plans={this.state.plans} usages={this.state.usages} ref="dataTable" />

        );
    }
});

var DataTable = React.createClass({
    render: function () {
        var _this = this;

        // Most of this is just building the data so that we can actually render it
        // such as finding the tier that someone would fall into, and calculating
        // the price
        if (this.props.usages && this.props.usages.length > 0 && this.props.plans && this.props.plans.length) {
            var carriers = this.props.plans.map(function(plan) {
                return {
                    value: plan.name,
                    color: plan.nameColor,
                    backgroundColor: plan.nameBackgroundColor,
                    url: plan.planUrl
                };
            });
            carriers.splice(0,0,{value:"Usage"});

            var sums = [];
            var usageCosts = this.props.usages.map(function(usage) {
                var usageCost = _this.props.plans.map(function(plan, index) {
                    var cost = plan.flexRanges.reduce(function(previousBestPrice, currentPlan) {
                        if (previousBestPrice) {
                            return previousBestPrice;
                        }

                        if (currentPlan.maxData >= usage) {
                            return currentPlan.price;
                        }

                        return null;
                    }, null);

                    if (! cost) {
                        var remaining = usage - plan.overage.includedData;
                        if (remaining % plan.overage.overageUnitSize > 0) {
                            remaining = remaining - (remaining % plan.overage.overageUnitSize) + plan.overage.overageUnitSize;
                        }
                        cost = (remaining / plan.overage.overageUnitSize) * plan.overage.overageUnitPrice + plan.overage.includedPrice;
                    }

                    sums[index] = (sums[index] ? sums[index] : 0) + cost;
                    return {value: "$" + (Math.round(cost * 100) / 100)};
                });
                usageCost.splice(0,0,{value:usage + " MB"});

                return <TableRow elements={usageCost} />
            });

            minSum = sums.reduce(function(previous,current){
                if (previous < current) {
                    return previous;
                }
                return current;
            });

            sums = sums.map(function(sum) {
                var sumValue = {value: "$" + (Math.round(sum / usageCosts.length * 100) / 100)};

                if (sum === minSum) {
                    sumValue["lowest"] = true;
                }
                return sumValue;
            });

            sums.splice(0,0,{value: "Average Cost"});

            return (

                                <TableRow head={true} elements={carriers} />

                                {usageCosts}
                                <TableRow elements={sums} />

            );
        }
        else {
            return (

            );
        }
    }
});

var TableRow = React.createClass({
    render: function () {
        var _this = this;
        var columns = this.props.elements.map(function(element) {
            var classes = "";
            var styles = {};

            if (element.color) {
                styles["color"] = element.color;
            }

            if (element.backgroundColor) {
                styles["background-color"] = element.backgroundColor;
            }

            if (element.lowest) {
                classes += "success";
            }

            if (_this.props.head) {
                if (element.url) {
                      return {element.value}
                } else {
                      return {element.value}
                }
            }
            else {
                return {element.value}	;
            }
        });

        return (

{columns}

        );
    }
});

var DataEntryForm = React.createClass({
    getInitialState: function() {
        return {
            usageUnit: "mb"
        };
    },
    handleSubmit: function(e) {
        var _this = this;

        e.preventDefault();
        var dataUsage = this.refs.dataUsage.getDOMNode().value.trim();

        if (!dataUsage) {
            return;
        }

        var usages = dataUsage.split(/\n/);
        usages = usages.map(function(usage) {
            usage = parseFloat(usage.trim());
            if (_this.state.usageUnit === "kb") {
                usage = usage / 1024;
            }
            return usage;
        });

        // Callback whoever is interested in our usage
        if (this.props.onDataEntered) {
            this.props.onDataEntered(usages);
        }
        return;
    },
    unitChanged: function (value) {
        this.state.usageUnit = value;
        this.setState(this.state);
    },
    sampleData: function (e) {
        e.preventDefault();
        $.ajax({
            url: "sample.data",
            dataType: 'text',
            success: function(data) {
                this.refs.dataUsage.getDOMNode().value = data;
            }.bind(this),
            error: function(xhr, status, err) {
                console.error("sample.data", status, err.toString());
            }.bind(this)
        });
    },
    render: function() {
        dataUsageTypes = [
            {
                label:'MB',
                value:'mb'
            },
            {
                label: 'KB',
                value: 'kb'
            }
        ];

        dataUsageSetName="usageUnit";

        return (
            <form data-role={"form"}>

                            <textarea name="dataUsage" className={"form-control"} ref="dataUsage" placeholder="Enter your data usage, with each month on a separate line" rows="5" />

                            <button className={"btn btn-default"} onClick={this.sampleData}>Get Sample Data</button>

                            Units
                            <RadioSet name="usageUnit" setName={"usageUnit"} options={dataUsageTypes} default={this.state.usageUnit} onChange={this.unitChanged} />

                            <button className={"btn btn-primary"} onClick={this.handleSubmit}>Calculate</button>

            </form>
        );
    }
});

var RadioSet = React.createClass({
    handleChange: function (event) {
        if (this.props.onChange) {
            this.props.onChange(event.target.value);
        }
    },
    render: function () {
        var _this = this;
        return (

                {this.props.options.map(function(option) {
                    var classes = "btn btn-default"
                    if (option.value === _this.props.default) {
                        classes += " active";
                    }

                    return <button type={"button"} className={classes} key={option.value} onClick={_this.handleChange} value={option.value}>{option.label}</button>
                })}

        );
    }
});

React.renderComponent(
    <DataCalculator plansUrl="plans.json" />,
    document.getElementById('react-content')
);<commit_msg>Added mixpanel tracking operations, so I could see how people actually use the app<commit_after>/** @jsx React.DOM */
var DataCalculator = React.createClass({
    getInitialState: function() {
        return {
            usages: [],
            plans: [],
            tableShown: false
        };
    },
    loadPlansFromServer: function() {
        $.ajax({
            url: this.props.plansUrl,
            dataType: 'json',
            success: function(plans) {
                this.state.plans = plans;
                this.setState(this.state);
            }.bind(this),
            error: function(xhr, status, err) {
                console.error(this.props.url, status, err.toString());
            }.bind(this)
        });
    },
    handleDataEntered: function(usages) {
        var _this = this;

        this.state.usages = usages;
        this.setState(this.state);

        // Set the timeout so that react has a chance to build the dom (especially the first time)
        // Before we attempt to slide the result in
        setTimeout(function(){
            $(_this.refs.dataTable.getDOMNode()).slideDown();
            var tableDiv = $(_this.refs.dataTable.getDOMNode())
            $("body").animate({scrollTop: tableDiv.position().top});
            _this.state.tableShown = true;
            _this.setState(this.state);
        },10);
    },
    componentDidMount: function() {
        this.loadPlansFromServer();
    },
    render: function () {
        tableStyles = {};
        if (!this.state.tableShown) {
            tableStyles['display'] = "none";
        }

        return (

                <DataEntryForm onDataEntered={this.handleDataEntered} />
                <DataTable styles={tableStyles} plans={this.state.plans} usages={this.state.usages} ref="dataTable" />

        );
    }
});

var DataTable = React.createClass({
    render: function () {
        var _this = this;

        // Most of this is just building the data so that we can actually render it
        // such as finding the tier that someone would fall into, and calculating
        // the price
        if (this.props.usages && this.props.usages.length > 0 && this.props.plans && this.props.plans.length) {
            var carriers = this.props.plans.map(function(plan) {
                return {
                    value: plan.name,
                    color: plan.nameColor,
                    backgroundColor: plan.nameBackgroundColor,
                    url: plan.planUrl
                };
            });
            carriers.splice(0,0,{value:"Usage"});

            var sums = [];
            var usageCosts = this.props.usages.map(function(usage) {
                var usageCost = _this.props.plans.map(function(plan, index) {
                    var cost = plan.flexRanges.reduce(function(previousBestPrice, currentPlan) {
                        if (previousBestPrice) {
                            return previousBestPrice;
                        }

                        if (currentPlan.maxData >= usage) {
                            return currentPlan.price;
                        }

                        return null;
                    }, null);

                    if (! cost) {
                        var remaining = usage - plan.overage.includedData;
                        if (remaining % plan.overage.overageUnitSize > 0) {
                            remaining = remaining - (remaining % plan.overage.overageUnitSize) + plan.overage.overageUnitSize;
                        }
                        cost = (remaining / plan.overage.overageUnitSize) * plan.overage.overageUnitPrice + plan.overage.includedPrice;
                    }

                    sums[index] = (sums[index] ? sums[index] : 0) + cost;
                    return {value: "$" + (Math.round(cost * 100) / 100)};
                });
                usageCost.splice(0,0,{value:usage + " MB"});

                return <TableRow elements={usageCost} />
            });

            minSum = sums.reduce(function(previous,current){
                if (previous < current) {
                    return previous;
                }
                return current;
            });

            var trackData = {};
            sums = sums.map(function(sum,index) {
                var roundedSum = Math.round(sum / usageCosts.length * 100) / 100
                var sumValue = {value: "$" + roundedSum};

                if (sum === minSum) {
                    sumValue["lowest"] = true;
                }
                trackData[this.props.plans[index].name + " Average Cost"] = roundedSum;
                return sumValue;
            }.bind(this));

            sums.splice(0,0,{value: "Average Cost"});
            mixpanel.track("Plans Shown",trackData);

            return (

                                <TableRow head={true} elements={carriers} />

                                {usageCosts}
                                <TableRow elements={sums} />

            );
        }
        else {
            return (

            );
        }
    }
});

var TableRow = React.createClass({
    render: function () {
        var _this = this;
        var columns = this.props.elements.map(function(element) {
            var classes = "";
            var styles = {};

            if (element.color) {
                styles["color"] = element.color;
            }

            if (element.backgroundColor) {
                styles["background-color"] = element.backgroundColor;
            }

            if (element.lowest) {
                classes += "success";
            }

            if (_this.props.head) {
                if (element.url) {
                      return {element.value}
                } else {
                      return {element.value}
                }
            }
            else {
                return {element.value}	;
            }
        });

        return (

{columns}

        );
    }
});

var DataEntryForm = React.createClass({
    getInitialState: function() {
        return {
            usageUnit: "mb"
        };
    },
    handleSubmit: function(e) {
        var _this = this;

        e.preventDefault();
        var dataUsage = this.refs.dataUsage.getDOMNode().value.trim();

        if (!dataUsage) {
            return;
        }

        var trackData = {}
        var sum = 0;
        var usages = dataUsage.split(/\n/);
        usages = usages.map(function(usage,index) {
            usage = parseFloat(usage.trim());
            if (_this.state.usageUnit === "kb") {
                usage = usage / 1024;
            }
            trackData['usage'+index] = usage;
            sum += usage;
            return usage;
        });

        trackData["unit"] = this.state.usageUnit;
        trackData["average"] = sum;
        mixpanel.track("Calculate Plans",trackData);

        // Callback whoever is interested in our usage
        if (this.props.onDataEntered) {
            this.props.onDataEntered(usages);
        }
        return;
    },
    unitChanged: function (value) {
        this.state.usageUnit = value;
        this.setState(this.state);
        mixpanel.track("Changed Units",{"unit":value});
    },
    sampleData: function (e) {
        e.preventDefault();
        mixpanel.track("Used Sample Data");
        $.ajax({
            url: "sample.data",
            dataType: 'text',
            success: function(data) {
                this.refs.dataUsage.getDOMNode().value = data;
            }.bind(this),
            error: function(xhr, status, err) {
                console.error("sample.data", status, err.toString());
            }.bind(this)
        });
    },
    render: function() {
        dataUsageTypes = [
            {
                label:'MB',
                value:'mb'
            },
            {
                label: 'KB',
                value: 'kb'
            }
        ];

        dataUsageSetName="usageUnit";

        return (
            <form data-role={"form"}>

                            <textarea name="dataUsage" className={"form-control"} ref="dataUsage" placeholder="Enter your data usage, with each month on a separate line" rows="5" />

                            <button className={"btn btn-default"} onClick={this.sampleData}>Get Sample Data</button>

                            Units
                            <RadioSet name="usageUnit" setName={"usageUnit"} options={dataUsageTypes} default={this.state.usageUnit} onChange={this.unitChanged} />

                            <button className={"btn btn-primary"} onClick={this.handleSubmit}>Calculate</button>

            </form>
        );
    }
});

var RadioSet = React.createClass({
    handleChange: function (event) {
        if (this.props.onChange) {
            this.props.onChange(event.target.value);
        }
    },
    render: function () {
        var _this = this;
        return (

                {this.props.options.map(function(option) {
                    var classes = "btn btn-default"
                    if (option.value === _this.props.default) {
                        classes += " active";
                    }

                    return <button type={"button"} className={classes} key={option.value} onClick={_this.handleChange} value={option.value}>{option.label}</button>
                })}

        );
    }
});

React.renderComponent(
    <DataCalculator plansUrl="plans.json" />,
    document.getElementById('react-content')
);<|endoftext|>


<commit_before>/*jslint node: true */
var express = require('express');
var session = require('express-session');
var path = require('path');
var swig = require('swig');
var q = require('q');
var logger = require('morgan');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var mongoClient = require('mongodb').MongoClient;

var GithubEvents = require('./routes/githubEvents');
var MongoRepository = require('./routes/mongoRepository');
var GithubOAuth = require('./routes/githubOAuth');
var QdService = require('./routes/qdService');
var app = express();

/*jslint nomen: true */
app.use(express.static(path.join(__dirname, 'public')));
/*jslint nomen: false */

app.use(logger());
app.use(cookieParser());
app.use(bodyParser.urlencoded({
    extended: true
}));

var winston = require('winston');
var filename = process.env.LOGGINGDIR ? path.join(process.env.LOGGINGDIR, 'github.log') : 'github.log';
winston.info('logging debug messages to ' + filename);
winston.add(winston.transports.File, { filename: filename, level: 'debug', json: false });
winston.error('Errors will be logged here');
winston.warn('Warns will be logged here');
winston.info('Info will be logged here');
winston.verbose('Verbose will be logged here');
winston.debug('Debug will be logged here');
winston.silly('Silly will be logged here');

winston.info('DBURI=' + process.env.DBURI);
var mongoUri = process.env.DBURI;

winston.info('PORT=' + process.env.PORT);
var port = process.env.PORT || 5001;

winston.info('SESSION_SECRET=' + process.env.SESSION_SECRET.substring(0,2) + '...');
var sessionSecret = process.env.SESSION_SECRET;

var logger = winston;

logger.logInfo = function(username, message, object){
    if(object) {
        logger.info(username + ': ' + message, object);
    }
    else {
        logger.info(username + ': ' + message, []);
    }
}

logger.logDebug = function(username, message, object){
    if(object) {
        logger.debug(username + ': ' + message, object);
    }
    else {
        logger.debug(username + ': ' + message, []);
    }
}

logger.logError = function(username, message, object){
    if(object) {
        logger.error(username + ': ' + message, object);
    }
    else {
        logger.error(username + ': ' + message, []);
    }
}

logger.logSilly = function(username, message, object){
    if(object) {
        logger.silly(username + ': ' + message, object);
    }
    else {
        logger.silly(username + ': ' + message, []);
    }
}

app.use(session({
    secret: sessionSecret,
    cookie: {
        maxAge: 2 * 365 * 24 * 60 * 60 * 1000, // 2 years
        secure: false // change to true when using https
    },
    resave: false, // don't save session if unmodified
    saveUninitialized: false // don't create session until something stored
}));

app.use(bodyParser.json());
app.engine('html', swig.renderFile);
app.set('views', __dirname + '/views');
app.set('view engine', 'html');

var attachLogger = function(req, res, next){
    req.logger = winston;
    next();
};
app.use(attachLogger);

var server = app.listen(port, function () {
    logger.logInfo('', 'Listening on ' + port);
});

var qdService = new QdService();

var mongoRepository;
var githubEvents;
var githubOAuth;
mongoClient.connect(mongoUri, function (err, databaseConnection) {
    if (err) {
        logger.logError('Could not connect to Mongodb with URI: ', [mongoUri, err]);
        process.exit(1);
    } else {
        logger.logInfo('connected to mongo: ', mongoUri);
        mongoRepository = new MongoRepository(databaseConnection);
        githubEvents = new GithubEvents(mongoRepository, qdService);
        githubOAuth = new GithubOAuth(app, mongoRepository, qdService);

        githubEvents.setLogger(logger);
    }
});

app.get('/', function (req, res) {
    //req.session.integrationUri = req.headers['x-forwarded-host'];
    req.session.appUri = req.headers.referer === undefined ? '/' : req.headers.referer.split('/').slice(0,3).join('/');
    process.env.appUri = req.session.appUri;
    req.session.oneselfUsername = req.query.username;
    req.session.registrationToken = req.query.token;
    logger.logInfo(req.query.username, 'github setup started: appUri, registrationToken', [req.session.appUri, req.query.token]);
    res.render('index');
});

app.get('/reauth', function (req, res) {
    if(req.query.username === undefined){
        res.render('reauthUnknownUser');
        return;
    }

    //req.session.integrationUri = req.headers['x-forwarded-host'];
    req.session.appUri = process.env.CONTEXT_URI;
    req.session.redirect = '/reauth/complete';
    req.session.reauth = true;
    req.session.username = req.query.username;
    logger.logInfo(req.query.username, 'reauthing', [req.session.appUri, req.query.token]);
    logger.logInfo(req.query.username, 'serving reauth page');
    res.render('reauth');
});

app.get('/reauth/complete', function (req, res) {
    //req.session.integrationUri = req.headers['x-forwarded-host'];
    req.session.appUri = null;
    req.session.redirect = null
    req.session.reauth = null;
    req.session.username = null;
    logger.logInfo(req.query.username, 'reauthing complete, ', [req.session.appUri, req.query.token]);
    logger.logDebug(req.query.username, 'serving reauth complete page');
    res.render('reauthcomplete');
});

// This is the entry point after auth, to do a sync. It's also used
// as the callback url in the stream
app.get('/authSuccess', function (req, res) {
    var githubUsername = req.query.username;
    var streamInfo = {
        streamid: req.query.streamid,
        writeToken: req.headers.authorization,
        lastSyncDate: req.query.latestSyncField
    };
    logger.logInfo(req.query.username, 'syncing data, [stream id, write token]', [streamInfo.streamid.substring(0, 2), streamInfo.writeToken.substring(0, 2)]);

    mongoRepository.findByGithubUsername(githubUsername)
        .then(function(user) {
            logger.logDebug(user.githubUsername, 'found in the database');
            var userInfo = {
                githubUsername: githubUsername,
                accessToken: user.accessToken,
                displayName: user.displayName,
                email: user.email
            };

            return githubEvents.sendGithubEvents(userInfo, streamInfo, process.env.appUri);
        })
        .catch(function(error){
            logger.logError(githubUsername, 'sync requested for unknown user');
        });

        res.status(200).send('ok, sync request acknowledged');
    }
);<commit_msg>added logging of error when sync request fails<commit_after>/*jslint node: true */
var express = require('express');
var session = require('express-session');
var path = require('path');
var swig = require('swig');
var q = require('q');
var logger = require('morgan');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var mongoClient = require('mongodb').MongoClient;

var GithubEvents = require('./routes/githubEvents');
var MongoRepository = require('./routes/mongoRepository');
var GithubOAuth = require('./routes/githubOAuth');
var QdService = require('./routes/qdService');
var app = express();

/*jslint nomen: true */
app.use(express.static(path.join(__dirname, 'public')));
/*jslint nomen: false */

app.use(logger());
app.use(cookieParser());
app.use(bodyParser.urlencoded({
    extended: true
}));

var winston = require('winston');
var filename = process.env.LOGGINGDIR ? path.join(process.env.LOGGINGDIR, 'github.log') : 'github.log';
winston.info('logging debug messages to ' + filename);
winston.add(winston.transports.File, { filename: filename, level: 'debug', json: false });
winston.error('Errors will be logged here');
winston.warn('Warns will be logged here');
winston.info('Info will be logged here');
winston.verbose('Verbose will be logged here');
winston.debug('Debug will be logged here');
winston.silly('Silly will be logged here');

winston.info('DBURI=' + process.env.DBURI);
var mongoUri = process.env.DBURI;

winston.info('PORT=' + process.env.PORT);
var port = process.env.PORT || 5001;

winston.info('SESSION_SECRET=' + process.env.SESSION_SECRET.substring(0,2) + '...');
var sessionSecret = process.env.SESSION_SECRET;

var logger = winston;

logger.logInfo = function(username, message, object){
    if(object) {
        logger.info(username + ': ' + message, object);
    }
    else {
        logger.info(username + ': ' + message, []);
    }
}

logger.logDebug = function(username, message, object){
    if(object) {
        logger.debug(username + ': ' + message, object);
    }
    else {
        logger.debug(username + ': ' + message, []);
    }
}

logger.logError = function(username, message, object){
    if(object) {
        logger.error(username + ': ' + message, object);
    }
    else {
        logger.error(username + ': ' + message, []);
    }
}

logger.logSilly = function(username, message, object){
    if(object) {
        logger.silly(username + ': ' + message, object);
    }
    else {
        logger.silly(username + ': ' + message, []);
    }
}

app.use(session({
    secret: sessionSecret,
    cookie: {
        maxAge: 2 * 365 * 24 * 60 * 60 * 1000, // 2 years
        secure: false // change to true when using https
    },
    resave: false, // don't save session if unmodified
    saveUninitialized: false // don't create session until something stored
}));

app.use(bodyParser.json());
app.engine('html', swig.renderFile);
app.set('views', __dirname + '/views');
app.set('view engine', 'html');

var attachLogger = function(req, res, next){
    req.logger = winston;
    next();
};
app.use(attachLogger);

var server = app.listen(port, function () {
    logger.logInfo('', 'Listening on ' + port);
});

var qdService = new QdService();

var mongoRepository;
var githubEvents;
var githubOAuth;
mongoClient.connect(mongoUri, function (err, databaseConnection) {
    if (err) {
        logger.logError('Could not connect to Mongodb with URI: ', [mongoUri, err]);
        process.exit(1);
    } else {
        logger.logInfo('connected to mongo: ', mongoUri);
        mongoRepository = new MongoRepository(databaseConnection);
        githubEvents = new GithubEvents(mongoRepository, qdService);
        githubOAuth = new GithubOAuth(app, mongoRepository, qdService);

        githubEvents.setLogger(logger);
    }
});

app.get('/', function (req, res) {
    //req.session.integrationUri = req.headers['x-forwarded-host'];
    req.session.appUri = req.headers.referer === undefined ? '/' : req.headers.referer.split('/').slice(0,3).join('/');
    process.env.appUri = req.session.appUri;
    req.session.oneselfUsername = req.query.username;
    req.session.registrationToken = req.query.token;
    logger.logInfo(req.query.username, 'github setup started: appUri, registrationToken', [req.session.appUri, req.query.token]);
    res.render('index');
});

app.get('/reauth', function (req, res) {
    if(req.query.username === undefined){
        res.render('reauthUnknownUser');
        return;
    }

    //req.session.integrationUri = req.headers['x-forwarded-host'];
    req.session.appUri = process.env.CONTEXT_URI;
    req.session.redirect = '/reauth/complete';
    req.session.reauth = true;
    req.session.username = req.query.username;
    logger.logInfo(req.query.username, 'reauthing', [req.session.appUri, req.query.token]);
    logger.logInfo(req.query.username, 'serving reauth page');
    res.render('reauth');
});

app.get('/reauth/complete', function (req, res) {
    //req.session.integrationUri = req.headers['x-forwarded-host'];
    req.session.appUri = null;
    req.session.redirect = null
    req.session.reauth = null;
    req.session.username = null;
    logger.logInfo(req.query.username, 'reauthing complete, ', [req.session.appUri, req.query.token]);
    logger.logDebug(req.query.username, 'serving reauth complete page');
    res.render('reauthcomplete');
});

// This is the entry point after auth, to do a sync. It's also used
// as the callback url in the stream
app.get('/authSuccess', function (req, res) {
    var githubUsername = req.query.username;
    var streamInfo = {
        streamid: req.query.streamid,
        writeToken: req.headers.authorization,
        lastSyncDate: req.query.latestSyncField
    };
    logger.logInfo(req.query.username, 'syncing data, [stream id, write token]', [streamInfo.streamid.substring(0, 2), streamInfo.writeToken.substring(0, 2)]);

    mongoRepository.findByGithubUsername(githubUsername)
        .then(function(user) {
            logger.logDebug(user.githubUsername, 'found in the database');
            var userInfo = {
                githubUsername: githubUsername,
                accessToken: user.accessToken,
                displayName: user.displayName,
                email: user.email
            };

            return githubEvents.sendGithubEvents(userInfo, streamInfo, process.env.appUri);
        })
        .catch(function(error){
            logger.logError(githubUsername, 'sync requested for unknown user', error);
        });

        res.status(200).send('ok, sync request acknowledged');
    }
);<|endoftext|>


<commit_before>// Copyright 2016, Google, Inc.
// Licensed under the Apache License, Version 2.0 (the 'License');
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an 'AS IS' BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

'use strict';

process.env.DEBUG = 'actions-on-google:*';
let Assistant = require('actions-on-google').ApiAiAssistant;
let express = require('express');
let bodyParser = require('body-parser');
let app = express();
app.use(bodyParser.json({type: 'application/json'}));

const CONFIRM_TYPE_CONTEXT = 'confirm_type';
const CLIENT_CODE_ACTION = 'get_client_code';
const EXPENSES_TYPE_ACTION = 'ask_expenses_or_services';
const EXPENSES_TYPE_ARGUMENT = 'codetype';
const CLIENT_NAME_ARGUMENT = 'clientname';

app.post('/', function (req, res) {
  const assistant = new Assistant({request: req, response: res});
  console.log('Request headers: ' + JSON.stringify(req.headers));
  console.log('Request body: ' + JSON.stringify(req.body));

  function askExpensesOrServices(assistant){
    let name = assistant.getArgument(CLIENT_NAME_ARGUMENT);
    assistant.setContext(CONFIRM_TYPE_CONTEXT);
    assistant.data.clientName = name;
    assistant.ask('You asked about ' + name + '.  Do you need an expenses or services code?');
  }

  function getClientCode (assistant) {
	  let type = assistant.getArgument(EXPENSES_TYPE_ARGUMENT);
    assistant.tell('I\'ll try to get the ' + assitant.data.clientName + ' ' + type + ' code.');
	  /*if (name === 'CRS'){
		  assistant.tell('The CRS services code is 1 2 5 0 0 0 2 3');
	  }
	  else{
	    assistant.ask ('Sorry, I dont know any ' + name + ' client codes.  Try again.');*/
	  }

  let actionMap = new Map();
  actionMap.set(CLIENT_CODE_ACTION, getClientCode);
  actionMap.set(EXPENSES_TYPE_ACTION, askExpensesOrServices);
  assistant.handleRequest(actionMap);
});

if (module === require.main) {
  // [START server]
  // Start the server
  let server = app.listen(process.env.PORT || 8080, function () {
    let port = server.address().port;
    console.log('App listening on port %s', port);
  });
  // [END server]
}

module.exports = app;
<commit_msg>misc fixes<commit_after>// Copyright 2016, Google, Inc.
// Licensed under the Apache License, Version 2.0 (the 'License');
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an 'AS IS' BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

'use strict';

process.env.DEBUG = 'actions-on-google:*';
let Assistant = require('actions-on-google').ApiAiAssistant;
let express = require('express');
let bodyParser = require('body-parser');
let app = express();
app.use(bodyParser.json({type: 'application/json'}));

const CONFIRM_TYPE_CONTEXT = 'confirm_type';
const CLIENT_CODE_ACTION = 'get_client_code';
const EXPENSES_TYPE_ACTION = 'ask_expenses_or_services';
const EXPENSES_TYPE_ARGUMENT = 'codetype';
const CLIENT_NAME_ARGUMENT = 'clientname';

app.post('/', function (req, res) {
  const assistant = new Assistant({request: req, response: res});
  console.log('Request headers: ' + JSON.stringify(req.headers));
  console.log('Request body: ' + JSON.stringify(req.body));

  function askExpensesOrServices(assistant){
    let name = assistant.getArgument(CLIENT_NAME_ARGUMENT);
    assistant.setContext(CONFIRM_TYPE_CONTEXT);
    assistant.data.clientName = name;
    assistant.ask('You asked about ' + name + '.  Do you need an expenses or services code?');
  }

  function getClientCode (assistant) {
	  let type = assistant.getArgument(EXPENSES_TYPE_ARGUMENT);
    assistant.tell('This works.');
    //assistant.tell('I\'ll try to get the ' + assitant.data.clientName + ' ' + type + ' code.');
	  /*if (name === 'CRS'){
		  assistant.tell('The CRS services code is 1 2 5 0 0 0 2 3');
	  }
	  else{
	    assistant.ask ('Sorry, I dont know any ' + name + ' client codes.  Try again.');*/
	  }

  let actionMap = new Map();
  actionMap.set(CLIENT_CODE_ACTION, getClientCode);
  actionMap.set(EXPENSES_TYPE_ACTION, askExpensesOrServices);
  assistant.handleRequest(actionMap);
});

if (module === require.main) {
  // [START server]
  // Start the server
  let server = app.listen(process.env.PORT || 8080, function () {
    let port = server.address().port;
    console.log('App listening on port %s', port);
  });
  // [END server]
}

module.exports = app;
<|endoftext|>


<commit_before>(function () {
    'use strict';

    function config($routeProvider) {
        var PARTIALS_PREFIX = 'views/partials/';
        var CONTROLLER_AS_VM = 'vm';

        $routeProvider
        .when('/', {
            templateUrl: PARTIALS_PREFIX + 'home.html',
            controller: 'HomeController',
            controllerAs: CONTROLLER_AS_VM
        })
        .when('/posts/:id', {
            templateUrl: PARTIALS_PREFIX + 'post.html',
            controller: 'PostController',
            controllerAs: CONTROLLER_AS_VM
        })
        .when('/results/:query', {
            templateUrl: PARTIALS_PREFIX + 'results.html',
            controller: 'ResultsController',
            controllerAs: CONTROLLER_AS_VM
        })
        .when('/category/:category', {
            templateUrl: PARTIALS_PREFIX + 'categories.html',
            controller: 'CategoryController',
            controllerAs: CONTROLLER_AS_VM
        })
        .otherwise({ redirectTo: '/' });
    }

    angular.module('theStyleApp.services', []);
    angular.module('theStyleApp.directives', []);
    angular.module('theStyleApp.filters', []);
    angular.module('theStyleApp.controllers', ['theStyleApp.services']);

    angular.module('theStyleApp', ['ngRoute', 'ngCookies', 'theStyleApp.controllers', 'theStyleApp.directives', 'theStyleApp.filters']) //
        .config(['$routeProvider', config])
        .constant('baseServiceUrl', 'http://localhost:7777/api/'); // Chage this when you migrate to heroku
        //.constant('baseServiceUrl', 'https://fast-badlands-79260.herokuapp.com/api/'); // Chage this when you migrate to heroku
}());<commit_msg>Included Heroku server url<commit_after>(function () {
    'use strict';

    function config($routeProvider) {
        var PARTIALS_PREFIX = 'views/partials/';
        var CONTROLLER_AS_VM = 'vm';

        $routeProvider
        .when('/', {
            templateUrl: PARTIALS_PREFIX + 'home.html',
            controller: 'HomeController',
            controllerAs: CONTROLLER_AS_VM
        })
        .when('/posts/:id', {
            templateUrl: PARTIALS_PREFIX + 'post.html',
            controller: 'PostController',
            controllerAs: CONTROLLER_AS_VM
        })
        .when('/results/:query', {
            templateUrl: PARTIALS_PREFIX + 'results.html',
            controller: 'ResultsController',
            controllerAs: CONTROLLER_AS_VM
        })
        .when('/category/:category', {
            templateUrl: PARTIALS_PREFIX + 'categories.html',
            controller: 'CategoryController',
            controllerAs: CONTROLLER_AS_VM
        })
        .otherwise({ redirectTo: '/' });
    }

    angular.module('theStyleApp.services', []);
    angular.module('theStyleApp.directives', []);
    angular.module('theStyleApp.filters', []);
    angular.module('theStyleApp.controllers', ['theStyleApp.services']);

    angular.module('theStyleApp', ['ngRoute', 'ngCookies', 'theStyleApp.controllers', 'theStyleApp.directives', 'theStyleApp.filters']) //
        .config(['$routeProvider', config])
        //.constant('baseServiceUrl', 'http://localhost:7777/api/'); // Chage this when you migrate to heroku
        .constant('baseServiceUrl', 'https://fast-badlands-79260.herokuapp.com/api/'); // Chage this when you migrate to heroku
}());<|endoftext|>


<commit_before>#!/usr/local/bin/node

/*
         __                            ___
        /\ \                     __  /'___\
        \ \ \         __     __ /\_\/\ \__/  __  __
         \ \ \  __  /'__`\ /'_ `\/\ \ \ ,__\/\ \/\ \
          \ \ \L\ \/\  __//\ \L\ \ \ \ \ \_/\ \ \_\ \
           \ \____/\ \____\ \____ \ \_\ \_\  \/`____ \
            \/___/  \/____/\/___L\ \/_/\/_/   `/___/> \
                             /\____/             /\___/
                             \_/__/              \/__/

        Copyright (c) 2013 by Legify UG. All Rights Reserved.

        Permission is hereby granted, free of charge, to any person obtaining
        a copy of this software and associated documentation files
        (the "Software"), to deal in the Software without restriction,
        including without limitation the rights to use, copy, modify, merge,
        publish, distribute, sublicense and to permit persons to whom the
        Software is furnished to do so, subject to the following conditions:

        The above copyright notice and this permission notice shall
        be included in all copies, substantial portions or derivates of the
        Software.

        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
        EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
        MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
        NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
        BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
        ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
        CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
*/

// Toggle when using Absinthe in production
// This will spread the process over all
// available processor cores.

// DO NOT toggle if your controllers
// use single-thread techologies
// like LevelDB (and its forks)
// or your app will die crucially.

// Make sure your data-endpoints
// are configured accordingly
// to support access from
// multiple Node processes.

GLOBAL.doCluster = false;

// Node won't display your
// controllers if you're
// clustering Absinthe.
//
GLOBAL.SERVE_INDEX = false;

var helpers = require("./helpers");
var _hr_mutate = helpers._hr_mutate;

var cluster = require('cluster');
var numCPUs = doCluster ? require('os').cpus().length : 1;

var worker = function() {
  // General purpose variable.
  var temp  = null;
  var _c_   = null;
  var _c    = null;

  // Used to substitute normal require if using V8
  var _require = null;

  // Constants
  var ABSINTHE = {
    version: function() {
      return '1';
    }
  };
  var DEFAULT_PORT    = 8080;
  var HTTP_DEFAULT_P  = 8081;

  // Loads many variables to the global environment
  require('./server_init').server_init();

  var port = config.port;

  _stream = require('stream').Stream;

  // Custom stream implementations
  var MemCache = require('./custom_memcache').MemCache(_stream);

  /*
      PRIMARY

          ctype &
                  001 - Array [& ]
                  010 - Object-Stat Hashmap
  */

  // TODO: Find out what is ctype.
  var readDictionary = function(start, ctype, callback) {
    var readDir = null;
    var stash   = {};

    if (ctype instanceof Function) {
      callback = ctype;
      ctype = 1;
    }

    // Callback gets status, files found and number of files.
    readDir = function(start, callback) {
      fs.lstat(start, function(err, stat) {
        if (err) { return callback(err); }

        var found = {
              dirs  : [],
              files : []
            },
            total     = 0,
            processed = 0;

        if (!stat.isDirectory()) {
          return false;
        } else {
          fs.readdir(start, function(err, files) {
            total = files.length;

            if (!total) { return callback(null, found, total); }

            files.forEach(function(file) {
              var abspath = _path.join(start, file);

              fs.stat(abspath, function(err, stat) {
                if (stat.isDirectory()) {
                  // TODO: What is the stash used for?
                  if (ctype === 1) { found.dirs.push(abspath); }
                  else if (ctype === 2) { stash[abspath] = stat; }

                  readDir(abspath, function(err, data) {
                    if (ctype === 1) {
                      found.dir   = found.dirs.concat(data.dirs);
                      found.files = found.files.concat(data.files);
                    }

                    processed += 1;
                    if (processed === total) { callback(null, found, stash); }
                  });
                } else {
                  if (ctype === 1) { found.files.push(abspath); }
                  else if (ctype === 2) { stash[abspath] = stat; }

                  processed += 1;
                  if (processed === total) { callback(null, found, stash); }
                }
              });
            });
          });
        }
      });
    };

    return readDir(start, function(a, b, c) {
      if (!(ctype ^ 3)) { return callback(b, c); }
      if (ctype & 1)    { return callback(b); }
      if (ctype & 2)    { return callback(c); }
    });
  };

  readDictionary('./static', 2, function (_fm) {
    var _fs               = {},
        _fs_cache         = {},
        _fs_cache_deflate = {},
        _fs_cache_gzip    = {};

    fs._createReadStream = fs.createReadStream;

    fs.createReadStream = function(path, options) {
      options = options || {};

      // whereas path is fd_ref && options is typeof object
      // __ if path, options do not statisfy (String path, Object options)
      // forward to base implementation.
      if (typeof path === 'string' &&
          typeof options === 'object' &&
          Object.keys(options).length > 0) {
        return fs._createReadStream.apply(this, arguments);
      }

      if (_fs_cache[path]) {
        return _fs_cache[path];
      }

      _fs_cache[path] = new MemCache();

      // Sends contents of file at 'path' to a buffer
      fs._createReadStream(path, options).pipe(_fs_cache[path]);
      return _fs_cache[path];
    };

    var err = _path.join(__dirname, 'lib/error/404.html');

    var cancel = function(response) {
      response.writeHead(404, {
          'Content-Type': 'text/html'
      });
      return fs.createReadStream(err).pipe(response);
    };

    var ucache = {};
    // Checks if path exists and decides which file to serve.
    var sanitize = function (uri, callback) {
      if (ucache[uri]) { return callback.apply(this, ucache[uri]); }

      var resvd = _path.join(process.cwd(), '/static', uri);

      fs.stat(resvd, function (err, stat) {
        if (err) {
          console.log('Error inside sanitize function.');
          console.dir(err);
          return callback(uri, resvd);
        }

        var isDirectory     = stat.isDirectory(),
            // when path is '/' serves index.html
            forceDelegation = uri.substr(-1) !== '/';

        // TODO: If path is a directory, what do you serve?
        if (isDirectory) {
          if (forceDelegation) {
            uri += '/';
          } else {
            uri += SERVE_INDEX ? 'index.html': '';
          }
        }

        ucache[uri] = [
          uri,
          _path.join(process.cwd(), '/static', uri),
          isDirectory && forceDelegation
        ];

        return callback.apply(this, ucache[uri]);
      });
    };

    spdy.createServer({
        ca: fs.readFileSync('./lib/tls/server.csr'),
        key: fs.readFileSync('./lib/tls/server.key'),
        cert: fs.readFileSync('./lib/tls/server.crt'),

        maxStreams: 100
    }, function (request, response) {
      var parsed  = url.parse(request.url),
          uri     = parsed.pathname,
          temp    = null;

      request._params = {};

      // Parse and format url params.
      if (parsed.query) {
        parsed.query.split('&').forEach(function(param) {
          temp = param.split('=');
          request._params[temp[0]] =
            decodeURIComponent(temp[1]).replace(/\+/g, ' ');
        });
      }

      sanitize(uri, function(uri, fn_, forceDelegation) {
        response._writeHead = response.writeHead;
        response.writeHead = function (statusCode, headers) {
          headers = headers || {};

          headers.libAbsinthe = 'r' + ABSINTHE.version;

          return response._writeHead.apply(this, [statusCode, headers]);
        };

        if (forceDelegation) {
          response.writeHead(307, {
              'Location': uri
          });
          return response.end();
        }

        // SECURITY: Cancel request if tries to access dirs
        // outside the project dir.
        if ( /\.\.\/\.\./.test(uri) || /\.\/\.\./.test(uri) ) {
          return cancel(response);
        }
        if ( fn_.length < (process.cwd()).length ) {
          return cancel(response);
        }
        if ( ~uri.indexOf('/../') ) {
          return cancel(response);
        }

        // ROUTER
        for (var router in controller) {
            // Why does route have no 'var'?
          for (var route in controller[router].paths) {
            temp = controller[router].paths[route]; // path name
            if ((uri.substr(0, temp.length) === temp && (uri.substr(temp.length, 1) == '/')) || uri === temp) {
              return controller[router].handler.apply(this, [
                request,
                response,
                controller[router].paths[route],
                uri
              ]);
            }
          }
        }

        // BLACKLIST
        rpaths = config.blacklist;

        for (var rpath in rpaths) {
          if (uri.substr(0, rpaths[rpath].length) === rpaths[rpath]) {
            response.writeHead(418, {
              'Content-Type': 'text/plain'
            });
            return response.end('418 I\'m a teapot\n');
          }
        }

        if (_fs[fn_] === void(0)) { _fs[fn_] = fs.existsSync(fn_); }

        if (!_fs[fn_]) { return cancel(response); }

        var s       = fs.createReadStream(fn_),
            etag    = _fm['static' + uri] && _fm['static' + uri].mtime || '0',
            ntag    = +etag;

        if (request.headers['if-none-match'] === ntag) {
          return response.end(response.writeHead(304, {
            'Date': etag.toString(),
            'Etag': ntag,
            'Cache-Control': 'max-age=86400, public',
            'Content-type': 'image/jpeg',
            'Keep-Alive': 'timeout=6, max=32',
            'Connection': 'keep-alive'
          }));
        }

        var aE        = request.headers['accept-encoding'] || '',
            _resHead  = {
              'Content-Type': mime.lookup(fn_),
              'Cache-control': 'max-age=604800',
              'Expire': new Date().toString(),
              'Etag': ntag
            };

        var compress = function(name, obj, cache) {
          _resHead['Content-Encoding'] = name;
          response.writeHead(200, _resHead);

          if (cache[fn_]) {
            return cache[fn_].pipe(response);
          }

          cache[fn_] = new MemCache();
          s.pipe(obj).pipe(cache[fn_]);
          return cache[fn_].pipe(response);
        };

        if (~aE.indexOf('deflate')) {
          return compress('deflate', zlib.createDeflate(), _fs_cache_deflate);

        } else if (~aE.indexOf('gzip')) {
          return compress('gzip', zlib.createGzip(), _fs_cache_gzip);

        } else {
          response.writeHead(200, _resHead);
          return s.pipe(response);
        }

      });
    }).listen(DEFAULT_PORT);

    http.createServer(function (request, response) {
      if (!request.headers.host) { response.end(); }

      return response.writeHead(302, {
              'Location': 'https://sly.mn' + request.url
      }), response.end();
    }).listen(HTTP_DEFAULT_P);

    console.log('[' + process.pid + '] Ready.');
  });
};

if (!cluster.isMaster) {
  worker();
} else {
  var init = process.hrtime(), vlist = {};

  console.log('Spawning..');

  for (var i = 0; i < numCPUs; i += 1) {
    cluster.fork();
  }

  cluster.on('online', function(worker) {
    'use strict';
    console.log('\t[' + worker.process.pid +
                '] Worker online. [' + _hr_mutate(init) + ']');

    vlist[worker.process.pid] = true;
  });

  cluster.on('disconnect', function(worker) {
    'use strict';
    if (!vlist[worker.process.pid]) { return false; }

    console.log('\t[' + worker.process.pid + '] Worker disconnected.');
    console.log('\tRespawning..');
    cluster.fork();

    delete vlist[worker.process.pid];
  });

  cluster.on('exit', function(worker, code, signal) {
    'use strict';
    if (!vlist[worker.process.pid]) { return false; }

    var exitCode = worker.process.exitCode;
    console.log('\t[' + worker.process.pid +
                '] Worker died. (' + exitCode + ')');
    console.log('\tRespawning..');
    cluster.fork();

    delete vlist[worker.process.pid];
  });
}
<commit_msg>More refactoring. So far I succeeded in flattening the readDirectory function.<commit_after>#!/usr/local/bin/node

/*
         __                            ___
        /\ \                     __  /'___\
        \ \ \         __     __ /\_\/\ \__/  __  __
         \ \ \  __  /'__`\ /'_ `\/\ \ \ ,__\/\ \/\ \
          \ \ \L\ \/\  __//\ \L\ \ \ \ \ \_/\ \ \_\ \
           \ \____/\ \____\ \____ \ \_\ \_\  \/`____ \
            \/___/  \/____/\/___L\ \/_/\/_/   `/___/> \
                             /\____/             /\___/
                             \_/__/              \/__/

        Copyright (c) 2013 by Legify UG. All Rights Reserved.

        Permission is hereby granted, free of charge, to any person obtaining
        a copy of this software and associated documentation files
        (the "Software"), to deal in the Software without restriction,
        including without limitation the rights to use, copy, modify, merge,
        publish, distribute, sublicense and to permit persons to whom the
        Software is furnished to do so, subject to the following conditions:

        The above copyright notice and this permission notice shall
        be included in all copies, substantial portions or derivates of the
        Software.

        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
        EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
        MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
        NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
        BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
        ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
        CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
*/

// Toggle when using Absinthe in production
// This will spread the process over all
// available processor cores.

// DO NOT toggle if your controllers
// use single-thread techologies
// like LevelDB (and its forks)
// or your app will die crucially.

// Make sure your data-endpoints
// are configured accordingly
// to support access from
// multiple Node processes.

GLOBAL.doCluster = false;

// Node won't display your
// controllers if you're
// clustering Absinthe.
//
GLOBAL.SERVE_INDEX = false;

var helpers = require("./helpers");
var _hr_mutate = helpers._hr_mutate;

var cluster = require('cluster');
var numCPUs = doCluster ? require('os').cpus().length : 1;

var worker = function() {
  // General purpose variable.
  var temp  = null;
  var _c_   = null;
  var _c    = null;

  // Used to substitute normal require if using V8
  var _require = null;

  // Constants
  var ABSINTHE = {
    version: function() {
      return '1';
    }
  };
  var DEFAULT_PORT    = 8080;
  var HTTP_DEFAULT_P  = 8081;

  // Loads many variables to the global environment
  require('./server_init').server_init();

  var port = config.port;

  _stream = require('stream').Stream;

  // Custom stream implementations
  var MemCache = require('./custom_memcache').MemCache(_stream);

  /*
      PRIMARY

          ctype &
                  001 - Array [& ]
                  010 - Object-Stat Hashmap
  */

  var addInfo = (function(ctype) {
    return function(stash, dict, path, stat) {
      if (ctype === 1) {
        dict.push(path);
      } else if (ctype === 2) {
        stash[path] = stat;
      }
    };
  }(ctype));

  readDir = function(start, ctype, callback) {
    var found = {
      dirs  : [],
      files : []
    };

    var processed      = 0;
    var dirContents    = null;
    var stash          = {};
    var stat           = null;
    var total          = 0;

    if (ctype instanceof Function) {
      callback = ctype;
      ctype = 1;
    }

    console.log('readDir callback: ');
    console.dir(callback);

    // Adds info to stash or found obj depending on
    // the ctype that was chosen.
    stat = fs.lstatSync(start);
    if (stat === void(0)) {
      callback(null);
    } else if (!stat.isDirectory()) {
      return false;
    }

    dirContents = fs.readdirSync(start);

    if (dirContents.length === 0) {
      return callback(null, found, total);
    }

    dirContents.forEach(function(file, i, dir) {
      var abspath  = null;
      var stat     = null;

      abspath = _path.join(start, file);
      stat = fs.statSync(abspath);
      if (stat === void(0)) {
        return callback(null);
      }

      if (!stat.isDirectory()) {
        addInfo(stash, found.files, abspath, stat);

        processed += 1;
        if (processed === dir.length) {
          callback(null, found, stash);
        }
      } else {
        addInfo(stash, found.dirs, abspath, stat);

        readDir(abspath, function(err, data) {
          if (ctype === 1) {
            found.dir   = found.dirs.concat(data.dirs);
            found.files = found.files.concat(data.files);
          }

          processed += 1;
          if (processed === total) {
            callback(null, found, stash);
          }
        });
      }
    });
  };

  // TODO: Find out what is ctype.
  var readDictionary = function(start, ctype, readDir, callback) {
    if (ctype instanceof Function) {
      callback = ctype;
      ctype = 1;
    }

    // Callback gets status, files found and number of files.
    return readDir(start, ctype, function(a, b, c) {
      if (!(ctype ^ 3)) {
        return callback(b, c);
      }
      if (ctype & 1) {
        return callback(b);
      }
      if (ctype & 2) {
        return callback(c);
      }
    });
  };

  readDictionary('./static', 2, readDir,
    function (_fm) {
      var _fs               = {};
      var _fs_cache         = {};
      var _fs_cache_deflate = {};
      var _fs_cache_gzip    = {};

      fs._createReadStream = fs.createReadStream;

      fs.createReadStream = function(path, options) {
        options = options || {};

        // whereas path is fd_ref && options is typeof object
        // __ if path, options do not statisfy (String path, Object options)
        // forward to base implementation.
        if (typeof path === 'string' &&
            typeof options === 'object' &&
            Object.keys(options).length > 0) {
          return fs._createReadStream.apply(this, arguments);
        }

        if (_fs_cache[path]) {
          return _fs_cache[path];
        }

        _fs_cache[path] = new MemCache();

        // Sends contents of file at 'path' to a buffer
        fs._createReadStream(path, options).pipe(_fs_cache[path]);
        return _fs_cache[path];
      };

      var err = _path.join(__dirname, 'lib/error/404.html');

      var cancel = function(response) {
        response.writeHead(404, {
            'Content-Type': 'text/html'
        });
        return fs.createReadStream(err).pipe(response);
      };

      var ucache = {};
      // Checks if path exists and decides which file to serve.
      var sanitize = function (uri, callback) {
        if (ucache[uri]) { return callback.apply(this, ucache[uri]); }

        var resvd = _path.join(process.cwd(), '/static', uri);

        fs.stat(resvd, function (err, stat) {
          if (err) {
            console.log('Error inside sanitize function.');
            console.dir(err);
            return callback(uri, resvd);
          }

          var isDirectory     = stat.isDirectory(),
              // when path is '/' serves index.html
              forceDelegation = uri.substr(-1) !== '/';

          // TODO: If path is a directory, what do you serve?
          if (isDirectory) {
            if (forceDelegation) {
              uri += '/';
            } else {
              uri += SERVE_INDEX ? 'index.html': '';
            }
          }

          ucache[uri] = [
            uri,
            _path.join(process.cwd(), '/static', uri),
            isDirectory && forceDelegation
          ];

          return callback.apply(this, ucache[uri]);
        });
      };

      spdy.createServer({
          ca: fs.readFileSync('./lib/tls/server.csr'),
          key: fs.readFileSync('./lib/tls/server.key'),
          cert: fs.readFileSync('./lib/tls/server.crt'),

          maxStreams: 100
      }, function (request, response) {
        var parsed  = url.parse(request.url),
            uri     = parsed.pathname,
            temp    = null;

        request._params = {};

        // Parse and format url params.
        if (parsed.query) {
          parsed.query.split('&').forEach(function(param) {
            temp = param.split('=');
            request._params[temp[0]] =
              decodeURIComponent(temp[1]).replace(/\+/g, ' ');
          });
        }

        sanitize(uri, function(uri, fn_, forceDelegation) {
          response._writeHead = response.writeHead;
          response.writeHead = function (statusCode, headers) {
            headers = headers || {};

            headers.libAbsinthe = 'r' + ABSINTHE.version;

            return response._writeHead.apply(this, [statusCode, headers]);
          };

          if (forceDelegation) {
            response.writeHead(307, {
                'Location': uri
            });
            return response.end();
          }

          // SECURITY: Cancel request if tries to access dirs
          // outside the project dir.
          if ( /\.\.\/\.\./.test(uri) || /\.\/\.\./.test(uri) ) {
            return cancel(response);
          }
          if ( fn_.length < (process.cwd()).length ) {
            return cancel(response);
          }
          if ( ~uri.indexOf('/../') ) {
            return cancel(response);
          }

          // ROUTER
          for (var router in controller) {
              // Why does route have no 'var'?
            for (var route in controller[router].paths) {
              temp = controller[router].paths[route]; // path name
              if ((uri.substr(0, temp.length) === temp && (uri.substr(temp.length, 1) == '/')) || uri === temp) {
                return controller[router].handler.apply(this, [
                  request,
                  response,
                  controller[router].paths[route],
                  uri
                ]);
              }
            }
          }

          // BLACKLIST
          rpaths = config.blacklist;

          for (var rpath in rpaths) {
            if (uri.substr(0, rpaths[rpath].length) === rpaths[rpath]) {
              response.writeHead(418, {
                'Content-Type': 'text/plain'
              });
              return response.end('418 I\'m a teapot\n');
            }
          }

          if (_fs[fn_] === void(0)) { _fs[fn_] = fs.existsSync(fn_); }

          if (!_fs[fn_]) { return cancel(response); }

          var s       = fs.createReadStream(fn_),
              etag    = _fm['static' + uri] && _fm['static' + uri].mtime || '0',
              ntag    = +etag;

          if (request.headers['if-none-match'] === ntag) {
            return response.end(response.writeHead(304, {
              'Date': etag.toString(),
              'Etag': ntag,
              'Cache-Control': 'max-age=86400, public',
              'Content-type': 'image/jpeg',
              'Keep-Alive': 'timeout=6, max=32',
              'Connection': 'keep-alive'
            }));
          }

          var aE        = request.headers['accept-encoding'] || '',
              _resHead  = {
                'Content-Type': mime.lookup(fn_),
                'Cache-control': 'max-age=604800',
                'Expire': new Date().toString(),
                'Etag': ntag
              };

          var compress = function(name, obj, cache) {
            _resHead['Content-Encoding'] = name;
            response.writeHead(200, _resHead);

            if (cache[fn_]) {
              return cache[fn_].pipe(response);
            }

            cache[fn_] = new MemCache();
            s.pipe(obj).pipe(cache[fn_]);
            return cache[fn_].pipe(response);
          };

          if (~aE.indexOf('deflate')) {
            return compress('deflate', zlib.createDeflate(), _fs_cache_deflate);

          } else if (~aE.indexOf('gzip')) {
            return compress('gzip', zlib.createGzip(), _fs_cache_gzip);

          } else {
            response.writeHead(200, _resHead);
            return s.pipe(response);
          }

        });
      }).listen(DEFAULT_PORT);

      http.createServer(function (request, response) {
        if (!request.headers.host) { response.end(); }

        return response.writeHead(302, {
                'Location': 'https://sly.mn' + request.url
        }), response.end();
      }).listen(HTTP_DEFAULT_P);

      console.log('[' + process.pid + '] Ready.');
    }
  );
};

if (!cluster.isMaster) {
  worker();
} else {
  var init = process.hrtime(), vlist = {};

  console.log('Spawning..');

  for (var i = 0; i < numCPUs; i += 1) {
    cluster.fork();
  }

  cluster.on('online', function(worker) {
    'use strict';
    console.log('\t[' + worker.process.pid +
                '] Worker online. [' + _hr_mutate(init) + ']');

    vlist[worker.process.pid] = true;
  });

  cluster.on('disconnect', function(worker) {
    'use strict';
    if (!vlist[worker.process.pid]) { return false; }

    console.log('\t[' + worker.process.pid + '] Worker disconnected.');
    console.log('\tRespawning..');
    cluster.fork();

    delete vlist[worker.process.pid];
  });

  cluster.on('exit', function(worker, code, signal) {
    'use strict';
    if (!vlist[worker.process.pid]) { return false; }

    var exitCode = worker.process.exitCode;
    console.log('\t[' + worker.process.pid +
                '] Worker died. (' + exitCode + ')');
    console.log('\tRespawning..');
    cluster.fork();

    delete vlist[worker.process.pid];
  });
}
<|endoftext|>


<commit_before>(function(exports) {
	client_id = 'cfd17821fa704f9d815a03cd2a80abaa';
	redirect_uri = 'https://spotify.dawson.fm/';

	g_access_token = '';
	g_username = '';

	var doLogin = function(callback) {
		var url = 'https://accounts.spotify.com/authorize?client_id=' + client_id +
			'&response_type=token' +
			'&scope=' + encodeURIComponent('playlist-read-private playlist-read-collaborative playlist-modify-public playlist-modify-private') +
			'&redirect_uri=' + encodeURIComponent(redirect_uri);
		window.location = url;
	}

	exports.startApp = function() {
		console.log('start app.');
		$('#start').click(function() {
			doLogin(function() {});
			}
		);
		// try getting an access_token
		var hash = location.hash.replace(/#/g, '');
		var all = hash.split('&');
		var args = {};
		console.log('all', all);
		all.forEach(function(keyvalue) {
			var idx = keyvalue.indexOf('=');
			var key = keyvalue.substring(0, idx);
			var val = keyvalue.substring(idx + 1);
			args[key] = val;
		});

		console.log('got args', args);

		if (typeof(args['access_token']) != 'undefined') {
			// got access token
			console.log('got access token', args['access_token']);
			g_access_token = args['access_token'];
		}

		if (g_access_token) {
			$('#start').hide();

			getUsername(function(username) {
				console.log('got username', username);
				g_username = username;

				refreshPlaylists();
			});
		}
	}

	$(document).on('click', '#playlist-list li a.sort', function (e) {
		var playlistA = $(this);

		playlistId = $(this).parent().attr('data-id');
		playlistName = $(this).parent().attr('data-name');
        username = $(this).parent().attr('data-owner');

		console.log("Sorting " + playlistName);
		$(this).text(" Sorting... ");

		getTracksForPlaylist(username, playlistId, function(tracks) {

			var oldTracks = JSON.parse(JSON.stringify(tracks.items));
			var newTracks = tracks.items;

			// all the magic happens here:
			newTracks.sort(function (a, b) {
				if (a.added_at > b.added_at) {
					return -1;
				}
				if (a.added_at < b.added_at) {
					return 1;
				}
				// a must be equal to b
				return 0;
			});

            $('#playlist-list').addClass('hide');

            sortTable = $('#sort-debug');
            sortTable.html('');
            sortTable.removeClass('hide');

            $.each(newTracks, function(i, row) {
                sortTable.append( '

' + oldTracks[i].track.name + '

' + newTracks[i].track.name + '

' );
            });

            sortTracks(username, playlistId, oldTracks, newTracks, function(resp) {
				console.log(resp);
				playlistA.text( "Sorted" );
				window.setTimeout(function() {
					playlistA.text( playlistName );
				}, 3000 );
			});
		});
	});

    $(document).on('click', '#playlist-list li a.copy', function (e) {
        var playlistA = $(this);

        playlistId = $(this).parent().attr('data-id');
        playlistName = $(this).parent().attr('data-name');
        username = $(this).parent().attr('data-owner');

        console.log("Copying " + playlistName);
        playlistA.text( "Copying..." );

        getTracksForPlaylist(username, playlistId, function(tracks) {

            copyPlaylist(g_username, playlistA.parent(), tracks, function(resp) {
                console.log(resp);
                playlistA.text( "Done" );
                window.setTimeout(function() {
                    playlistA.text( 'Copy' );
                }, 3000 );
            });
        });
    });

function refreshPlaylists() {

    getPlaylists(g_username, function(playlist) {
        console.log('got playlist', playlist);

        playlist.items.sort(function(a,b) {
            if (a.name > b.name) {
                return 1;
            }
            if (a.name < b.name) {
                return -1;
            }
            // a must be equal to b
            return 0;
        });

        $('#playlist-list').html('');

        $.each(playlist.items, function(i, row) {
            $('#playlist-list').append('

' + row.name + ' (' + row.tracks.total + ' tracks) vCopy

');
        });

        //$('#playlist-list').listview('refresh');
    });
}

function sortTracks(username, playlistId, oldTracks, newTracks, callback) {
	console.log("sortTracks " + playlistId);

	sortTable = $('#sort-debug');
    $.each(newTracks, function(i, row) {
		$('#sort-debug .row').eq(i).html( '
' + oldTracks[i].track.name + '

' + newTracks[i].track.name + '
' );
    });

	$.each(newTracks, function (i, row) {
		if (row.track.id != oldTracks[i].track.id) {
			console.log("track " + i + "in wrong position");

			var iOld = oldTracks.findIndex(function ( element, index, array ) {
					return ( element.track.id == row.track.id );
				});

			moveTrackFromTo(
				username,
                playlistId,
				iOld,
				i,
				function (resp) {
					if ( resp == null) return;

					var minusOne = oldTracks.slice(0,iOld).concat(oldTracks.slice(iOld+1));

                    if (i > iOld)
                        i = i - 1;

					var oldSorted = minusOne.slice(0,i).concat([oldTracks[iOld]]).concat(minusOne.slice(i));

					sortTracks(username, playlistId, oldSorted, newTracks, callback);
				}
			);

			return false;
		}
	});

	callback(true);
}

function moveTrackFromTo(username, playlist, oldI, newI, callback ) {
    var json = JSON.stringify({ "range_start": oldI, "insert_before": newI });

	console.log('moveTrackFromTo ', json );

	var url = 'https://api.spotify.com/v1/users/' + username + '/playlists/' + playlist + '/tracks';

    callback(url);
    return;

	$.ajax(url, {
		method: 'PUT',
		data: json,
		headers: {
			'Authorization': 'Bearer ' + g_access_token,
			'Accept': 'application/json',
			'Content-Type': 'application/json'
		},
		success: function(r) {
			callback(r);
		},
		error: function(r) {
            console.log(r.responseText);
			callback(null);
		}
	});
}

	function getUsername(callback) {
	console.log('getUsername');
	var url = 'https://api.spotify.com/v1/me';
	$.ajax(url, {
		dataType: 'json',
		headers: {
			'Authorization': 'Bearer ' + g_access_token
		},
		success: function(r) {
			callback(r.id);
		},
		error: function(r) {
            console.log(r.responseText);
			callback(null);
		}
	});
}

function getPlaylists(username, callback) {
	console.log('getPlaylists', username);
	var url = 'https://api.spotify.com/v1/users/' + username + '/playlists/';

	$.ajax(url, {
		method: 'GET',
		headers: {
			'Authorization': 'Bearer ' + g_access_token,
			'Accept': 'application/json'
		},
		success: function(r) {
			callback(r);
		},
		error: function(r) {
            console.log(r.responseText);
			callback(null);
		}
	});
}

function getTracksForPlaylist(username, playlist, callback) {
	console.log('getTracksForPlaylist', username, playlist);
	var url = 'https://api.spotify.com/v1/users/' + username + '/playlists/' + playlist + '/tracks';

	$.ajax(url, {
		method: 'GET',
		headers: {
			'Authorization': 'Bearer ' + g_access_token,
			'Accept': 'application/json'
		},
		success: function(r) {
			callback(r);
		},
		error: function(r) {
            console.log(r.responseText);
			callback(null);
		}
	});
}

function copyPlaylist(username, element, tracks, callback) {
	playlist = element.attr('data-name') + ' Copy';

	console.log('copyPlaylist', playlist);

    var trackList = {
        uris : []
    }

    // construct a reversed track list
    $.each(tracks.items, function(i, row) {
        trackList.uris = trackList.uris.concat(["spotify:track:" + row.track.id]);
    });

    var url = 'https://api.spotify.com/v1/users/' + username + '/playlists/';
	$.ajax(url, {
		method: 'POST',
		data: JSON.stringify({ name: playlist, public: true}),
		headers: {
			'Authorization': 'Bearer ' + g_access_token,
			'Accept': 'application/json',
			'Content-Type': 'application/json'
		},
		success: function(r) {
            setTracksForPlaylist(username, r.id, trackList, callback);
		},
		error: function(r) {
            console.log(r.responseText);
			callback(null);
		}
	});

}

function setTracksForPlaylist(username, playlist, tracks, callback) {
	console.log('setTracksForPlaylist', tracks, playlist);

    var url = 'https://api.spotify.com/v1/users/' + username + '/playlists/' + playlist + '/tracks';

    $.ajax(url, {
        method: 'PUT',
        data: JSON.stringify(tracks),
        headers: {
            'Authorization': 'Bearer ' + g_access_token,
            'Accept': 'application/json',
            'Content-Type': 'application/json'
        },
        success: function(r) {
            callback(r);
        },
        error: function(r) {
            console.log(r.responseText);
            callback(null);
        }
    });
}

})(window);
<commit_msg>add timer<commit_after>(function(exports) {
	client_id = 'cfd17821fa704f9d815a03cd2a80abaa';
	redirect_uri = 'https://spotify.dawson.fm/';

	g_access_token = '';
	g_username = '';

	var doLogin = function(callback) {
		var url = 'https://accounts.spotify.com/authorize?client_id=' + client_id +
			'&response_type=token' +
			'&scope=' + encodeURIComponent('playlist-read-private playlist-read-collaborative playlist-modify-public playlist-modify-private') +
			'&redirect_uri=' + encodeURIComponent(redirect_uri);
		window.location = url;
	}

	exports.startApp = function() {
		console.log('start app.');
		$('#start').click(function() {
			doLogin(function() {});
			}
		);
		// try getting an access_token
		var hash = location.hash.replace(/#/g, '');
		var all = hash.split('&');
		var args = {};
		console.log('all', all);
		all.forEach(function(keyvalue) {
			var idx = keyvalue.indexOf('=');
			var key = keyvalue.substring(0, idx);
			var val = keyvalue.substring(idx + 1);
			args[key] = val;
		});

		console.log('got args', args);

		if (typeof(args['access_token']) != 'undefined') {
			// got access token
			console.log('got access token', args['access_token']);
			g_access_token = args['access_token'];
		}

		if (g_access_token) {
			$('#start').hide();

			getUsername(function(username) {
				console.log('got username', username);
				g_username = username;

				refreshPlaylists();
			});
		}
	}

	$(document).on('click', '#playlist-list li a.sort', function (e) {
		var playlistA = $(this);

		playlistId = $(this).parent().attr('data-id');
		playlistName = $(this).parent().attr('data-name');
        username = $(this).parent().attr('data-owner');

		console.log("Sorting " + playlistName);
		$(this).text(" Sorting... ");

		getTracksForPlaylist(username, playlistId, function(tracks) {

			var oldTracks = JSON.parse(JSON.stringify(tracks.items));
			var newTracks = tracks.items;

			// all the magic happens here:
			newTracks.sort(function (a, b) {
				if (a.added_at > b.added_at) {
					return -1;
				}
				if (a.added_at < b.added_at) {
					return 1;
				}
				// a must be equal to b
				return 0;
			});

            $('#playlist-list').addClass('hide');

            sortTable = $('#sort-debug');
            sortTable.html('');
            sortTable.removeClass('hide');

            $.each(newTracks, function(i, row) {
                sortTable.append( '

' + oldTracks[i].track.name + '

' + newTracks[i].track.name + '

' );
            });

            sortTracks(username, playlistId, oldTracks, newTracks, function(resp) {
				console.log(resp);
				window.setTimeout(function() {
					refreshPlaylists();
				}, 3000 );
			});
		});
	});

    $(document).on('click', '#playlist-list li a.copy', function (e) {
        var playlistA = $(this);

        playlistId = $(this).parent().attr('data-id');
        playlistName = $(this).parent().attr('data-name');
        username = $(this).parent().attr('data-owner');

        console.log("Copying " + playlistName);
        playlistA.text( "Copying..." );

        getTracksForPlaylist(username, playlistId, function(tracks) {

            copyPlaylist(g_username, playlistA.parent(), tracks, function(resp) {
                console.log(resp);
                playlistA.text( "Done" );
                window.setTimeout(function() {
                    playlistA.text( 'Copy' );
                }, 3000 );
            });
        });
    });

function refreshPlaylists() {

    getPlaylists(g_username, function(playlist) {
        console.log('got playlist', playlist);

        playlist.items.sort(function(a,b) {
            if (a.name > b.name) {
                return 1;
            }
            if (a.name < b.name) {
                return -1;
            }
            // a must be equal to b
            return 0;
        });

		$('#sort-debug').addClass('hide');
        $('#playlist-list').html('');
		$('#playlist-list').removeClass('hide');

        $.each(playlist.items, function(i, row) {
            $('#playlist-list').append('

' + row.name + ' (' + row.tracks.total + ' tracks) vCopy

');
        });

        //$('#playlist-list').listview('refresh');
    });
}

function sortTracks(username, playlistId, oldTracks, newTracks, callback) {
	console.log("sortTracks " + playlistId);

	sortTable = $('#sort-debug');
    $.each(newTracks, function(i, row) {
		$('#sort-debug .row').eq(i).html( '
' + oldTracks[i].track.name + '

' + newTracks[i].track.name + '
' );
    });

	$.each(newTracks, function (i, row) {
		if (row.track.id != oldTracks[i].track.id) {
			console.log("track " + i + "in wrong position");

			var iOld = oldTracks.findIndex(function ( element, index, array ) {
					return ( element.track.id == row.track.id );
				});

			moveTrackFromTo(
				username,
                playlistId,
				iOld,
				i,
				function (resp) {
					if ( resp == null) return;

					var minusOne = oldTracks.slice(0,iOld).concat(oldTracks.slice(iOld+1));

                    if (i > iOld)
                        i = i - 1;

					var oldSorted = minusOne.slice(0,i).concat([oldTracks[iOld]]).concat(minusOne.slice(i));

					window.setTimeout(sortTracks(username, playlistId, oldSorted, newTracks, callback), 500);
				}
			);

			return false;
		}
	});

	callback(true);
}

function moveTrackFromTo(username, playlist, oldI, newI, callback ) {
    var json = JSON.stringify({ "range_start": oldI, "insert_before": newI });

	console.log('moveTrackFromTo ', json );

	var url = 'https://api.spotify.com/v1/users/' + username + '/playlists/' + playlist + '/tracks';

    callback(url);
    return;

	$.ajax(url, {
		method: 'PUT',
		data: json,
		headers: {
			'Authorization': 'Bearer ' + g_access_token,
			'Accept': 'application/json',
			'Content-Type': 'application/json'
		},
		success: function(r) {
			callback(r);
		},
		error: function(r) {
            console.log(r.responseText);
			callback(null);
		}
	});
}

	function getUsername(callback) {
	console.log('getUsername');
	var url = 'https://api.spotify.com/v1/me';
	$.ajax(url, {
		dataType: 'json',
		headers: {
			'Authorization': 'Bearer ' + g_access_token
		},
		success: function(r) {
			callback(r.id);
		},
		error: function(r) {
            console.log(r.responseText);
			callback(null);
		}
	});
}

function getPlaylists(username, callback) {
	console.log('getPlaylists', username);
	var url = 'https://api.spotify.com/v1/users/' + username + '/playlists/';

	$.ajax(url, {
		method: 'GET',
		headers: {
			'Authorization': 'Bearer ' + g_access_token,
			'Accept': 'application/json'
		},
		success: function(r) {
			callback(r);
		},
		error: function(r) {
            console.log(r.responseText);
			callback(null);
		}
	});
}

function getTracksForPlaylist(username, playlist, callback) {
	console.log('getTracksForPlaylist', username, playlist);
	var url = 'https://api.spotify.com/v1/users/' + username + '/playlists/' + playlist + '/tracks';

	$.ajax(url, {
		method: 'GET',
		headers: {
			'Authorization': 'Bearer ' + g_access_token,
			'Accept': 'application/json'
		},
		success: function(r) {
			callback(r);
		},
		error: function(r) {
            console.log(r.responseText);
			callback(null);
		}
	});
}

function copyPlaylist(username, element, tracks, callback) {
	playlist = element.attr('data-name') + ' Copy';

	console.log('copyPlaylist', playlist);

    var trackList = {
        uris : []
    }

    // construct a reversed track list
    $.each(tracks.items, function(i, row) {
        trackList.uris = trackList.uris.concat(["spotify:track:" + row.track.id]);
    });

    var url = 'https://api.spotify.com/v1/users/' + username + '/playlists/';
	$.ajax(url, {
		method: 'POST',
		data: JSON.stringify({ name: playlist, public: true}),
		headers: {
			'Authorization': 'Bearer ' + g_access_token,
			'Accept': 'application/json',
			'Content-Type': 'application/json'
		},
		success: function(r) {
            setTracksForPlaylist(username, r.id, trackList, callback);
		},
		error: function(r) {
            console.log(r.responseText);
			callback(null);
		}
	});

}

function setTracksForPlaylist(username, playlist, tracks, callback) {
	console.log('setTracksForPlaylist', tracks, playlist);

    var url = 'https://api.spotify.com/v1/users/' + username + '/playlists/' + playlist + '/tracks';

    $.ajax(url, {
        method: 'PUT',
        data: JSON.stringify(tracks),
        headers: {
            'Authorization': 'Bearer ' + g_access_token,
            'Accept': 'application/json',
            'Content-Type': 'application/json'
        },
        success: function(r) {
            callback(r);
        },
        error: function(r) {
            console.log(r.responseText);
            callback(null);
        }
    });
}

})(window);
<|endoftext|>


<commit_before>/*
var express = require('express');
var path = require('path');
var favicon = require('static-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var signed_request = require('./signed_request')

var routes = require('./routes/index');
var users = require('./routes/users');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

app.use(favicon());
app.use(logger('dev'));
app.use(bodyParser());
//app.use(bodyParser.json());
//app.use(bodyParser.urlencoded());
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', routes);
app.use('/users', users);

/// catch 404 and forwarding to error handler
app.use(function(req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
});

/// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
    app.use(function(err, req, res, next) {
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: err
        });
    });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: {}
    });
});

module.exports = app;

var server = app.listen(3000, function() {
    console.log('Listening on port %d', server.address().port);
});
*/
var express = require('express');
var bodyParser = require('body-parser');
var signed_request = require('./signed_request')
var app = express();

app.use(bodyParser());

app.get('/hello.txt', function(req, res){
  console.log(req);
  res.send('Hello World');
});

app.post('/canvas', function(req, res){
  //console.log(req);

  secret = '9199412244496712486';
  var verifier = new SignedRequest(secret, req.body.signed_request);
  verifier.verify(); // whether or not the signed request verifies
  verifier.data; // the data from the signed request
  res.send(verifier.data);
  res.send('Hello World');
});

//app.set('port', process.env.PORT || 3000);

var server = app.listen(process.env.PORT || 3000, function() {
    console.log('Listening on port %d', server.address().port);
});<commit_msg>cleanup of code in app.js<commit_after>var express = require('express');
var bodyParser = require('body-parser');
var signed_request = require('./signed_request')
var app = express();

app.use(bodyParser());

app.post('/canvas', function(req, res){
  secret = process.env.SECRET;
  var verifier = new SignedRequest(secret, req.body.signed_request);
  verifier.verify(); // whether or not the signed request verifies ()
  verifier.data; // the data from the signed request
  res.send(verifier.data);
});

var server = app.listen(process.env.PORT || 3000, function() {
    console.log('Listening on port %d', server.address().port);
});<|endoftext|>


<commit_before>#!/usr/bin/env node

//
// Detects triangles and quadrilaterals
//

// sourced from: https://github.com/peterbraden/node-opencv/tree/master/examples

var cv = require('opencv'),
  colors = require("colors"),
  Spacebrew = require('./sb-1.3.0').Spacebrew,
  sb,
  config = require("./machine"),
  fs = require("fs"),
  PNG = require("png");

/**
*
* Spacebrew setup
*
**/
sb = new Spacebrew.Client( config.server, config.name, config.description );  // create spacebrew client object

// create the spacebrew subscription channels
sb.addPublish("config", "string", "");  // publish config for handshake
sb.addSubscribe("config", "boolean"); // subscription for config handshake

sb.addSubscribe("image", "binary.png");  // subscription for receiving image binary

sb.addPublish("src", "string", "");   // publish image url for handshake

sb.onBooleanMessage = onBooleanMessage;
sb.onCustomMessage = onCustomMessage;
sb.onOpen = onOpen;

// connect to spacbrew
sb.connect();

/**
 * Function that is called when Spacebrew connection is established
 */
function onOpen(){
  console.log( "Connected through Spacebrew as: " + sb.name() + "." );
}

function onCustomMessage( name, value, type ){

  switch(type){
    case "binary.png":
      if(name == "image"){
        var png = new Png(value, 640, 480, 'rgb', 8);

        var png_image = png.encodeSync();

        fs.writeFileSync('./test.png', png_image.toString('binary'), 'binary');
      }
  }
}

var lowThresh = 0;
var highThresh = 100;
var nIters = 2;
var minArea = 2000;

var BLUE = [0, 255, 0]; //B, G, R
var RED   = [0, 0, 255]; //B, G, R
var GREEN = [0, 255, 0]; //B, G, R
var WHITE = [255, 255, 255]; //B, G, R

/*
cv.readImage('../test/square2.jpg', function(err, im) {

  var out = new cv.Matrix(im.height(), im.width());

  // convert the image to grey scale
  im.convertGrayscale();

  //make a copy of the image called im_canny (not sure why?)
  im_canny = im.copy();

  im_canny.canny(lowThresh, highThresh);
  im_canny.dilate(nIters);

//uses a for loop to find number of contours
  contours = im_canny.findContours();

  for(i = 0; i < contours.size(); i++) {

    if(contours.area(i) < minArea) continue;

    // arcLength tells you how long each face is, so that you can cut out any small shape
    var arcLength = contours.arcLength(i, true);
    contours.approxPolyDP(i, 0.01 * arcLength, true);

    // chooses a drawing color based on number of contours
    switch(contours.cornerCount(i)) {
    case 3:
      out.drawContour(contours, i, GREEN);
      break;
    case 4:
      out.drawContour(contours, i, RED);
      break;
    case 5:
    out.drawContour(contours,i, BLUE);
    break;
    default:
      out.drawContour(contours, i, WHITE);

    }
  }

//saves image
  out.save('../test/out.png');
});
*/<commit_msg>added boolean message handler<commit_after>#!/usr/bin/env node

//
// Detects triangles and quadrilaterals
//

// sourced from: https://github.com/peterbraden/node-opencv/tree/master/examples

var cv = require('opencv'),
  colors = require("colors"),
  Spacebrew = require('./sb-1.3.0').Spacebrew,
  sb,
  config = require("./machine"),
  fs = require("fs"),
  PNG = require("png");

/**
*
* Spacebrew setup
*
**/
sb = new Spacebrew.Client( config.server, config.name, config.description );  // create spacebrew client object

// create the spacebrew subscription channels
sb.addPublish("config", "string", "");  // publish config for handshake
sb.addSubscribe("config", "boolean"); // subscription for config handshake

sb.addSubscribe("image", "binary.png");  // subscription for receiving image binary

sb.addPublish("src", "string", "");   // publish image url for handshake

sb.onBooleanMessage = onBooleanMessage;
sb.onCustomMessage = onCustomMessage;
sb.onOpen = onOpen;

// connect to spacbrew
sb.connect();

/**
 * Function that is called when Spacebrew connection is established
 */
function onOpen(){
  console.log( "Connected through Spacebrew as: " + sb.name() + "." );
}

function onCustomMessage( name, value, type ){

  switch(type){
    case "binary.png":
      if(name == "image"){
        var png = new Png(value, 640, 480, 'rgb', 8);

        var png_image = png.encodeSync();

        fs.writeFileSync('./test.png', png_image.toString('binary'), 'binary');
      }
  }
}

/**
 * onStringMessage Function that is called whenever new spacebrew string messages are received.
 *          It accepts two parameters:
 * @param  {String} name    Holds name of the subscription feed channel
 * @param  {String} value   Holds value received from the subscription feed
 */
function onBooleanMessage( name, value ){

  console.log("[onBooleanMessage] value: " + value + " name: " + name);

  switch(name){
    case "config":
      console.log([
          // Timestamp
          String(+new Date()).grey,
          // Message
          String("sending config").cyan
        ].join(" "));

      sb.send("config", "string", JSON.stringify( config ) );
      break;
  }
}

var lowThresh = 0;
var highThresh = 100;
var nIters = 2;
var minArea = 2000;

var BLUE = [0, 255, 0]; //B, G, R
var RED   = [0, 0, 255]; //B, G, R
var GREEN = [0, 255, 0]; //B, G, R
var WHITE = [255, 255, 255]; //B, G, R

/*
cv.readImage('../test/square2.jpg', function(err, im) {

  var out = new cv.Matrix(im.height(), im.width());

  // convert the image to grey scale
  im.convertGrayscale();

  //make a copy of the image called im_canny (not sure why?)
  im_canny = im.copy();

  im_canny.canny(lowThresh, highThresh);
  im_canny.dilate(nIters);

//uses a for loop to find number of contours
  contours = im_canny.findContours();

  for(i = 0; i < contours.size(); i++) {

    if(contours.area(i) < minArea) continue;

    // arcLength tells you how long each face is, so that you can cut out any small shape
    var arcLength = contours.arcLength(i, true);
    contours.approxPolyDP(i, 0.01 * arcLength, true);

    // chooses a drawing color based on number of contours
    switch(contours.cornerCount(i)) {
    case 3:
      out.drawContour(contours, i, GREEN);
      break;
    case 4:
      out.drawContour(contours, i, RED);
      break;
    case 5:
    out.drawContour(contours,i, BLUE);
    break;
    default:
      out.drawContour(contours, i, WHITE);

    }
  }

//saves image
  out.save('../test/out.png');
});
*/<|endoftext|>


<commit_before>/**
 * Copyright (C) 2016 yanni4night.com
 * app.js
 *
 * changelog
 * 2016-04-13[17:51:10]:revised
 *
 * @author yanni4night@gmail.com
 * @version 1.0.0
 * @since 1.0.0
 */
require('babel-core/register')({
    presets: ['es2015-node5', 'stage-3', 'react']
});

const path = require('path');
const antiaris = require('./kernel/');
const conf = require('./conf/');

const app = antiaris.bootstrap({
    appDir: path.join(__dirname, 'app'),
    confDir: path.join(__dirname, 'conf'),
    middlewareDir: path.join(__dirname, 'middleware')
});

console.log(`Listening at ${conf.PORT}`);
app.listen(conf.PORT);<commit_msg>remove es2015/stage-3 babel compiling temporarily<commit_after>/**
 * Copyright (C) 2016 yanni4night.com
 * app.js
 *
 * changelog
 * 2016-04-13[17:51:10]:revised
 *
 * @author yanni4night@gmail.com
 * @version 1.0.0
 * @since 1.0.0
 */
require('babel-core/register')({
    presets: [/*'es2015-node5', 'stage-3',*/ 'react']
});

const path = require('path');
const antiaris = require('./kernel/');
const conf = require('./conf/');

const app = antiaris.bootstrap({
    appDir: path.join(__dirname, 'app'),
    confDir: path.join(__dirname, 'conf'),
    middlewareDir: path.join(__dirname, 'middleware')
});

console.log(`Listening at ${conf.PORT}`);
app.listen(conf.PORT);<|endoftext|>


<commit_before>
const port = process.env.PORT || 3000;
const app = exports.app = require('express')();
const path = require('path');
const fs = require('fs');
const request = require('request');

app.get('/', (req, res) => {
	res.send('Welcome');
});

app.get('/ical', (req, res) => {
	var icalUrl = 'https://raw.githubusercontent.com/rhargreaves/ical-sed/master/test/data/one_event.ics';
	request.get(icalUrl, (error, response, body) => {
		if(error) {
			console.log(error);
			return;
		}
		res.send(body);
	});

	res.sendFile(path.join(__dirname, 'test/data/one_event.ics'));
});

app.listen(port);
<commit_msg>Parse and save to ICS<commit_after>
const port = process.env.PORT || 3000;
const app = exports.app = require('express')();
const path = require('path');
const fs = require('fs');
const request = require('request');
const ICalParser = require('cozy-ical').ICalParser;

app.get('/', (req, res) => {
	res.send('Welcome');
});

app.get('/ical', (req, res) => {
	var icalUrl = 'https://raw.githubusercontent.com/rhargreaves/ical-sed/master/test/data/one_event.ics';
	request.get(icalUrl, (error, response, body) => {
		if(error) {
			console.log(error);
			return;
		}

		var parser = new ICalParser();
		parser.parseString(body, function(err, cal) {
			var strCal = cal.toString();
			res.setHeader('content-type', 'text/calendar');
			res.send(strCal);
		});
	});
});

app.listen(port);
<|endoftext|>