<commit_before>var A4gPlugin = (function (Phaser) {
    function optionalRemove(tagId) {
        var el = document.getElementById(tagId);

        if (el && el.parentNode) {
            el.parentNode.removeChild(el);
        }
    }

    function getGameContainer(game) {
        return typeof game.parent === 'string' ? document.getElementById(game.parent) : game.parent;
    }

    function getGameContainerId(game) {
        var container = getGameContainer(game);

        if (!container.id) {
            container.id = 'a4g-id-' + Math.round(Math.random() * 100000);
        }

        return container.id;
    }

    function getGameWidth(game) {
        return getGameContainer(game).offsetWidth;
    }

    function getGameHeight(game) {
        return getGameContainer(game).offsetHeight;
    }

    function A4gPlugin(game, pluginManager) {
        Phaser.Plugin.call(this, game, pluginManager);

        this.adTypes = ['video'];
        this.zone = null;
    }

    A4gPlugin.configure = function (config) {
        var preconfiguredPlugin = function (game, pluginManager) {
            A4gPlugin.call(this, game, pluginManager);

            if (config.zone) {
                this.zone = config.zone;
            }

            if (config.adEndpoint) {
                this.adEndpoint = config.adEndpoint;
            }

            if (config.skipOffset) {
                this.skipOffset = config.skipOffset;
            }

            if (config.adTypes) {
                this.adTypes = config.adTypes;
            }
        };
        preconfiguredPlugin.prototype = Object.create(A4gPlugin.prototype);
        return preconfiguredPlugin;
    };

    A4gPlugin.prototype = Object.create(Phaser.Plugin.prototype);

    A4gPlugin.prototype.adEndpoint = 'ads.ad4game.com/www/delivery/video.php';
    A4gPlugin.prototype.skipOffset = 10;

    A4gPlugin.prototype.showAd = function (zone) {
        var scriptEl = document.createElement('SCRIPT'),
            antiCache = Math.round(Math.random() * 100000),
            game = this.game,
            callbackFn = 'a4gcb' + Math.round(Math.random() * 100000),
            tid,
            registeredCallback = function () {
                setTimeout(function () {
                    game.paused = false;
                }, 500);
                clearTimeout(tid);
                window[callbackFn] = function () {};
            };
        tid = setTimeout(registeredCallback, 30000)
        game.paused = true;

        optionalRemove('A4Gwrap');
        optionalRemove('a4gpreloader');

        window[callbackFn] = registeredCallback;
        scriptEl.onerror = registeredCallback;

        scriptEl.async = true;
        scriptEl.type = 'text/javascript';
        scriptEl.src = '//' + this.adEndpoint +
            '?zoneid=' + (zone || this.zone) +
            '&width=' + getGameWidth(game) +
            '&height=' + getGameHeight(game) +
            '&adtype=' + this.adTypes.join('_') +
            '&cb=' + callbackFn +
            '&disableflash=1' +
            '&siteurl=' + location.href +
            '&wrapper=' + getGameContainerId(game) +
            '&skipoffset=' + this.skipOffset
            '&autoplay=1' +
            '&l=' + antiCache;

        getGameContainer(game).insertAdjacentElement('afterend', scriptEl);
    };

    return A4gPlugin;
} (window.Phaser));
<commit_msg>Add support for fallback zone<commit_after>var A4gPlugin = (function (Phaser) {
    function optionalRemove(tagId) {
        var el = document.getElementById(tagId);

        if (el && el.parentNode) {
            el.parentNode.removeChild(el);
        }
    }

    function getGameContainer(game) {
        return typeof game.parent === 'string' ? document.getElementById(game.parent) : game.parent;
    }

    function getGameContainerId(game) {
        var container = getGameContainer(game);

        if (!container.id) {
            container.id = 'a4g-id-' + Math.round(Math.random() * 100000);
        }

        return container.id;
    }

    function getGameWidth(game) {
        return getGameContainer(game).offsetWidth;
    }

    function getGameHeight(game) {
        return getGameContainer(game).offsetHeight;
    }

    function appendExtraParams(url, extraParams) {
        var extraParamsPairs = [];

        for (var extraParamName in extraParams) {
            extraParamsPairs.push(extraParamName + '=' + encodeURIComponent(extraParams[extraParamName]));
        }

        return url + (extraParamsPairs.length ? '&' + extraParamsPairs.join('&') : '');
    }

    function A4gPlugin(game, pluginManager) {
        Phaser.Plugin.call(this, game, pluginManager);

        this.adTypes = ['video'];
        this.zone = null;
        this.extraParams = {};
    }

    A4gPlugin.configure = function (config) {
        var preconfiguredPlugin = function (game, pluginManager) {
            A4gPlugin.call(this, game, pluginManager);

            if (config.zone) {
                this.zone = config.zone;
            }

            if (config.adEndpoint) {
                this.adEndpoint = config.adEndpoint;
            }

            if (config.skipOffset) {
                this.skipOffset = config.skipOffset;
            }

            if (config.adTypes) {
                this.adTypes = config.adTypes;
            }

            if (config.fallbackZone) {
                this.extraParams.fajszone = config.fallbackZone;
            }
        };
        preconfiguredPlugin.prototype = Object.create(A4gPlugin.prototype);
        return preconfiguredPlugin;
    };

    A4gPlugin.prototype = Object.create(Phaser.Plugin.prototype);

    A4gPlugin.prototype.adEndpoint = 'ads.ad4game.com/www/delivery/video.php';
    A4gPlugin.prototype.skipOffset = 10;

    A4gPlugin.prototype.showAd = function (zone) {
        var scriptEl = document.createElement('SCRIPT'),
            antiCache = Math.round(Math.random() * 100000),
            game = this.game,
            callbackFn = 'a4gcb' + Math.round(Math.random() * 100000),
            tid,
            registeredCallback = function () {
                setTimeout(function () {
                    game.paused = false;
                }, 500);
                clearTimeout(tid);
                window[callbackFn] = function () {};
            };
        tid = setTimeout(registeredCallback, 30000)
        game.paused = true;

        optionalRemove('A4Gwrap');
        optionalRemove('a4gpreloader');

        window[callbackFn] = registeredCallback;
        scriptEl.onerror = registeredCallback;

        scriptEl.async = true;
        scriptEl.type = 'text/javascript';
        scriptEl.src = appendExtraParams('//' + this.adEndpoint +
            '?zoneid=' + (zone || this.zone) +
            '&width=' + getGameWidth(game) +
            '&height=' + getGameHeight(game) +
            '&adtype=' + this.adTypes.join('_') +
            '&cb=' + callbackFn +
            '&disableflash=1' +
            '&siteurl=' + location.href +
            '&wrapper=' + getGameContainerId(game) +
            '&skipoffset=' + this.skipOffset
            '&autoplay=1' +
            '&l=' + antiCache, this.extraParams);

        getGameContainer(game).insertAdjacentElement('afterend', scriptEl);
    };

    return A4gPlugin;
} (window.Phaser));
<|endoftext|>


<commit_before>import request from 'request-promise';
import GitHub from './github';
import GITHUB_MESSAGE_TYPES from './github-message-types';
import { log, saveState, emptyState }from './log';

const CI_PROVIDER = {
    travis:   'travis',
    appveyor: 'appveyor'
};

const TRAVIS_API_HEADERS = {
    'Travis-API-Version': 3,
    'Authorization':      `token ${process.env.TRAVIS_TOKEN}`
};

const APPVEYOR_API_HEADERS = { 'Authorization': `bearer ${process.env.APPVEYOR_TOKEN}` };

function getCiApiHeaders (providerType) {
    switch (providerType) {
        case CI_PROVIDER.travis:
            return TRAVIS_API_HEADERS;

        case CI_PROVIDER.appveyor:
            return APPVEYOR_API_HEADERS;
    }
}

export default class MessagesHandler {
    constructor (bot, state, collaborator) {
        this.bot    = bot;
        this.github = new GitHub(bot.name, bot.token);

        if (collaborator)
            this.collaboratorGithub = new GitHub(collaborator.name, collaborator.token);

        this.state = state || emptyState();

        this.SYNCHRONIZE_TIMEOUT = 5 * 60 * 1000;
    }

    _saveState () {
        var prs   = Object.keys(this.state.openedPullRequests);
        var state = {
            openedPullRequests: {}
        };

        for (var i = 0; i < prs.length; i++) {
            var pr    = this.state.openedPullRequests[prs[i]];
            var clone = {};

            for (var field in pr) {
                if (pr.hasOwnProperty(field) && field !== 'syncTimeout' && field !== 'waitForTestsTimeout')
                    clone[field] = pr[field];
            }

            state.openedPullRequests[prs[i]] = clone;
        }

        saveState(state);
    }

    static _getPRName (repo, id) {
        return `${repo}/${id}`;
    }

    static _getTestBranchName (issueId) {
        return 'rp-' + issueId;
    }

    static _getTemporaryBranchName (branchName) {
        return 'build-bot-temp-' + branchName;
    }

    static _getMark (state) {
        return state === 'success' ? ':white_check_mark:' : ':x:';
    }

    static _getCILink (status) {
        return `[${MessagesHandler._getMark(status.state)} ${status.context}](${status.target_url})`;
    }

    static _getDetails (statuses) {
        if (statuses.length === 1)
            return `[details](${statuses[0].target_url})`;

        return 'details:\n\n' +
            statuses
                .map(status => `* ${MessagesHandler._getCILink(status)}`)
                .join('\n\n');
    }

    _getPRBySha (repo, sha) {
        var prNumbers = Object.keys(this.state.openedPullRequests);

        var prId = prNumbers.filter((id) => {
            var pr = this.state.openedPullRequests[id];

            return (pr.sha === sha || pr.travisConfSha === sha) && pr.repo === repo;
        })[0];

        return prId ? this.state.openedPullRequests[prId] : null;
    }

    _createBranch (repo, owner, prSha, branchName, travisConf, prNumber) {
        if (!travisConf)
            return this.github.createBranch(repo, prSha, branchName);

        var temporaryBranchName = MessagesHandler._getTemporaryBranchName(branchName);
        var commitMessage       = '';

        this.github.createBranch(repo, prSha, temporaryBranchName)
            .then(() => this.github.getCommitMessage(repo, owner, prSha))
            .then(message => {
                commitMessage = message;

                return this.github
                    .deleteFile(repo, 'appveyor.yml', temporaryBranchName, commitMessage)
                    .catch(err => {
                        if (err.status === 'Not Found')
                            return;

                        throw err;
                    });
            })
            .then(() => {
                return this.github.replaceFile(repo, '.travis.yml', `.travis-${travisConf}.yml`,
                    temporaryBranchName, commitMessage);
            })
            .then(commitSha => {
                this.github.createBranch(repo, commitSha, branchName);

                var currentPr = this.state.openedPullRequests[MessagesHandler._getPRName(repo, prNumber)];

                currentPr.travisConfSha = commitSha;

                this._saveState();
            });
    }

    _syncBranchWithCommit (repo, owner, branchName, prSha, travisConf, prNumber) {
        if (!travisConf)
            return this.github.syncBranchWithCommit(repo, branchName, prSha);

        var temporaryBranchName = MessagesHandler._getTemporaryBranchName(branchName);
        var commitMessage       = '';

        this.github.syncBranchWithCommit(repo, temporaryBranchName, prSha)
            .then(() => this.github.getCommitMessage(repo, owner, prSha))
            .then(message => {
                commitMessage = message;

                return this.github
                    .deleteFile(repo, 'appveyor.yml', temporaryBranchName, commitMessage)
                    .catch(err => {
                        if (err.status === 'Not Found')
                            return;

                        throw err;
                    });
            })
            .then(() => {
                return this.github.replaceFile(repo, '.travis.yml', `.travis-${travisConf}.yml`,
                    temporaryBranchName, commitMessage);
            })
            .then(commitSha => {
                this.github.syncBranchWithCommit(repo, branchName, commitSha);

                var currentPr = this.state.openedPullRequests[MessagesHandler._getPRName(repo, prNumber)];

                currentPr.travisConfSha = commitSha;

                this._saveState();
            });
    }

    _getTravisConf (prTitle) {
        if (prTitle.indexOf('[docs]') > -1)
            return 'docs';

        return null;
    }

    _onPROpened (repo, prNumber, prSha, branchName, owner, title) {
        var existedPr = this.state.openedPullRequests[MessagesHandler._getPRName(repo, prNumber)];
        var pr        = existedPr || {};

        pr.number        = prNumber;
        pr.sha           = prSha;
        pr.repo          = repo;
        pr.owner         = owner;
        pr.branchName    = branchName;
        pr.travisConfSha = null;

        this.state.openedPullRequests[MessagesHandler._getPRName(repo, prNumber)] = pr;

        this._saveState();

        if (existedPr)
            this._syncBranchWithCommit(repo, owner, branchName, prSha, this._getTravisConf(title), prNumber);
        else
            this._createBranch(repo, owner, prSha, branchName, this._getTravisConf(title), prNumber);
    }

    _onPRClosed (repo, prNumber, branchName, title) {
        var prName = MessagesHandler._getPRName(repo, prNumber);
        var pr     = this.state.openedPullRequests[prName];

        clearTimeout(pr.waitForTestsTimeout);
        clearTimeout(pr.syncTimeout);

        delete this.state.openedPullRequests[prName];

        this._saveState();

        var travisConf = this._getTravisConf(title);

        this.github.deleteBranch(repo, branchName);

        if (travisConf)
            this.github.deleteBranch(repo, MessagesHandler._getTemporaryBranchName(branchName));
    }

    _waitForTestsStart (pr, repo, owner, sha, statuses) {
        var handler = this;

        if (pr.waitForTestsTimeout) {
            clearTimeout(pr.waitForTestsTimeout);
            pr.waitForTestsTimeout = null;
        }

        pr.timeToTests = Math.round(this.SYNCHRONIZE_TIMEOUT / 60000);

        function setStatus (time) {
            var message = `Tests will start in ${time} minute(s).`;

            statuses.forEach(status => (handler.collaboratorGithub ||
                handler.github).createStatus(repo, owner, sha, 'pending', '', message, status.context));

            if (time) {
                pr.waitForTestsTimeout = setTimeout(() => {
                    pr.waitForTestsTimeout = null;
                    pr.timeToTests--;

                    if (pr.timeToTests)
                        setStatus(pr.timeToTests);
                }, 60 * 1000);
            }
        }

        setStatus(pr.timeToTests);
    }

    async _onPRSynchronized (repo, prNumber, branchName, sha, owner, title) {
        var pr = this.state.openedPullRequests[MessagesHandler._getPRName(repo, prNumber)];

        if (!pr)
            return;

        var statusInfo = await this.github.getCombinedStatus(repo, this.bot.name, branchName);

        pr.sha = sha;

        if (pr.syncTimeout) {
            clearTimeout(pr.syncTimeout);
            delete pr.syncTimeout;
        }

        pr.syncTimeout = setTimeout(() => {
            delete pr.syncTimeout;
            this._saveState();

            this._syncBranchWithCommit(repo, owner, branchName, sha, this._getTravisConf(title), prNumber);
        }, this.SYNCHRONIZE_TIMEOUT);

        this._saveState();

        this._waitForTestsStart(pr, repo, owner, sha, statusInfo.statuses);
    }

    _onPRMessage (body) {
        if (/temp-pr/.test(body.pull_request.base.ref))
            return;

        var owner          = body.repository.owner.login;
        var repo           = body.repository.name;
        var prSha          = body.pull_request.head.sha;
        var prId           = body.pull_request.id;
        var title          = body.pull_request.title;
        var prNumber       = body.number;
        var testBranchName = MessagesHandler._getTestBranchName(prId);

        if (/opened/.test(body.action))
            this._onPROpened(repo, prNumber, prSha, testBranchName, owner, title);

        if (body.action === 'closed')
            this._onPRClosed(repo, prNumber, testBranchName, title);

        if (body.action === 'synchronize')
            this._onPRSynchronized(repo, prNumber, testBranchName, prSha, owner, title);
    }

    async _onStatusMessage (body) {
        log('Status message: ' + JSON.stringify(body, null, 4));

        if (body.repository.owner.login !== this.bot.name)
            return;

        var repo = body.repository.name;

        var pr = this._getPRBySha(repo, body.sha);

        if (!pr)
            return;

        var statusInfo = await this.github.getCombinedStatus(repo, this.bot.name, pr.branchName);

        if (statusInfo.sha !== body.sha)
            return;

        var owner = pr.owner;

        (this.collaboratorGithub || this.github).createStatus(repo, owner, pr.sha, body.state, body.target_url,
            body.description, body.context);

        if (statusInfo.state === 'pending' || statusInfo.statuses.some(status => status.state === 'pending'))
            return;

        var status  = statusInfo.state === 'success' ? 'passed' : 'failed';
        var mark    = MessagesHandler._getMark(statusInfo.state);
        var details = MessagesHandler._getDetails(statusInfo.statuses);

        this.github.createPullRequestComment(repo, pr.number,
            `${mark} Tests for the commit ${pr.sha} have ${status}. See ${details}.`, owner, repo);
    }

    _onIssueCommentMessage (body) {
        if (body.action !== 'created')
            return;

        var owner = body.repository.owner.login;
        var repo  = body.repository.name;
        var pr    = this.state.openedPullRequests[MessagesHandler._getPRName(repo, body.issue.number)];

        if (!pr)
            return;

        var commandHandler = this._getCommandHandler(body.comment.body, body.issue.title);

        if (!commandHandler)
            return;

        this.github.isUserCollaborator(repo, owner, body.comment.user.login)
            .then(isCollaborator => {
                if (isCollaborator)
                    commandHandler(pr);
            });
    }

    async _requestCiApi (providerType, opts) {
        return request(Object.assign({
            json:    true,
            headers: getCiApiHeaders(providerType)
        }, opts));
    }

    async _restartTravis (pr) {
        const repoSlug = encodeURIComponent(this.bot.name + '/' + pr.repo);

        const branchInfo = await this._requestCiApi(CI_PROVIDER.travis, {
            url: `https://api.travis-ci.org/repo/${repoSlug}/branch/${pr.branchName}`
        });

        const lastBuild = branchInfo['last_build'];

        const lastBuildInfo = await this._requestCiApi(CI_PROVIDER.travis, {
            url: `https://api.travis-ci.org/build/${lastBuild.id}?include=job.state`
        });

        const restartRequests = [];

        for (const job of lastBuildInfo.jobs) {
            if (job.state !== 'passed') {
                restartRequests.push(this._requestCiApi(CI_PROVIDER.travis, {
                    url:    `https://api.travis-ci.org/job/${job.id}/restart`,
                    method: 'POST'
                }));
            }
        }

        await Promise.all(restartRequests);
    }

    async _restartAppveyor (pr) {
        await this._requestCiApi(CI_PROVIDER.appveyor, {
            url:    'https://ci.appveyor.com/api/builds',
            method: 'POST',

            body: {
                accountName: this.bot.name,
                projectSlug: pr.repo,
                branch:      pr.branchName
            }
        });
    }

    async _restartFailedTasks (pr) {
        const statusInfo = await this.github.getCombinedStatus(pr.repo, this.bot.name, pr.branchName);

        if (statusInfo.statuses.some(status => status.state === 'pending') || pr.syncTimeout)
            return;

        const failedStatuses = statusInfo.statuses.filter(status => status.state !== 'success');

        for (const status of failedStatuses) {
            if (status.context.startsWith('continuous-integration/appveyor'))
                await this._restartAppveyor(pr);
            else if (status.context.startsWith('continuous-integration/travis-ci'))
                await this._restartTravis(pr);
        }
    }

    async _restartAllTasks (pr, { title }) {
        var statusInfo = await this.github.getCombinedStatus(pr.repo, this.bot.name, pr.branchName);

        if (statusInfo.statuses.some(status => status.state === 'pending') || pr.syncTimeout)
            return;

        this._syncBranchWithCommit(pr.repo, pr.owner, pr.branchName, pr.sha, this._getTravisConf(title), pr.number);
    }

    _getCommandHandler (message, title) {
        var name = this.bot.name;

        if (message.indexOf(`@${name}`) < 0)
            return null;

        message = message.replace(`@${name}`, '').replace(/\s/g, '').replace(/^[\/\\]/, '');

        switch (message) {
            case 'retest-all':
            case 'restart-all':
                return pr => this._restartAllTasks(pr, { title });
            case 'retest':
            case 'restart':
                return pr => this._restartFailedTasks(pr, { title });
            default:
                return null;
        }
    }

    handle (message) {
        if (message.type === GITHUB_MESSAGE_TYPES.pullRequest)
            this._onPRMessage(message.body);

        if (message.type === GITHUB_MESSAGE_TYPES.status)
            this._onStatusMessage(message.body);

        if (message.type === GITHUB_MESSAGE_TYPES.issueComment)
            this._onIssueCommentMessage(message.body);
    }
}
<commit_msg>Add force commands<commit_after>import request from 'request-promise';
import GitHub from './github';
import GITHUB_MESSAGE_TYPES from './github-message-types';
import { log, saveState, emptyState }from './log';

const CI_PROVIDER = {
    travis:   'travis',
    appveyor: 'appveyor'
};

const TRAVIS_API_HEADERS = {
    'Travis-API-Version': 3,
    'Authorization':      `token ${process.env.TRAVIS_TOKEN}`
};

const APPVEYOR_API_HEADERS = { 'Authorization': `bearer ${process.env.APPVEYOR_TOKEN}` };

function getCiApiHeaders (providerType) {
    switch (providerType) {
        case CI_PROVIDER.travis:
            return TRAVIS_API_HEADERS;

        case CI_PROVIDER.appveyor:
            return APPVEYOR_API_HEADERS;
    }
}

export default class MessagesHandler {
    constructor (bot, state, collaborator) {
        this.bot    = bot;
        this.github = new GitHub(bot.name, bot.token);

        if (collaborator)
            this.collaboratorGithub = new GitHub(collaborator.name, collaborator.token);

        this.state = state || emptyState();

        this.SYNCHRONIZE_TIMEOUT = 5 * 60 * 1000;
    }

    _saveState () {
        var prs   = Object.keys(this.state.openedPullRequests);
        var state = {
            openedPullRequests: {}
        };

        for (var i = 0; i < prs.length; i++) {
            var pr    = this.state.openedPullRequests[prs[i]];
            var clone = {};

            for (var field in pr) {
                if (pr.hasOwnProperty(field) && field !== 'syncTimeout' && field !== 'waitForTestsTimeout')
                    clone[field] = pr[field];
            }

            state.openedPullRequests[prs[i]] = clone;
        }

        saveState(state);
    }

    static _getPRName (repo, id) {
        return `${repo}/${id}`;
    }

    static _getTestBranchName (issueId) {
        return 'rp-' + issueId;
    }

    static _getTemporaryBranchName (branchName) {
        return 'build-bot-temp-' + branchName;
    }

    static _getMark (state) {
        return state === 'success' ? ':white_check_mark:' : ':x:';
    }

    static _getCILink (status) {
        return `[${MessagesHandler._getMark(status.state)} ${status.context}](${status.target_url})`;
    }

    static _getDetails (statuses) {
        if (statuses.length === 1)
            return `[details](${statuses[0].target_url})`;

        return 'details:\n\n' +
            statuses
                .map(status => `* ${MessagesHandler._getCILink(status)}`)
                .join('\n\n');
    }

    _getPRBySha (repo, sha) {
        var prNumbers = Object.keys(this.state.openedPullRequests);

        var prId = prNumbers.filter((id) => {
            var pr = this.state.openedPullRequests[id];

            return (pr.sha === sha || pr.travisConfSha === sha) && pr.repo === repo;
        })[0];

        return prId ? this.state.openedPullRequests[prId] : null;
    }

    _createBranch (repo, owner, prSha, branchName, travisConf, prNumber) {
        if (!travisConf)
            return this.github.createBranch(repo, prSha, branchName);

        var temporaryBranchName = MessagesHandler._getTemporaryBranchName(branchName);
        var commitMessage       = '';

        this.github.createBranch(repo, prSha, temporaryBranchName)
            .then(() => this.github.getCommitMessage(repo, owner, prSha))
            .then(message => {
                commitMessage = message;

                return this.github
                    .deleteFile(repo, 'appveyor.yml', temporaryBranchName, commitMessage)
                    .catch(err => {
                        if (err.status === 'Not Found')
                            return;

                        throw err;
                    });
            })
            .then(() => {
                return this.github.replaceFile(repo, '.travis.yml', `.travis-${travisConf}.yml`,
                    temporaryBranchName, commitMessage);
            })
            .then(commitSha => {
                this.github.createBranch(repo, commitSha, branchName);

                var currentPr = this.state.openedPullRequests[MessagesHandler._getPRName(repo, prNumber)];

                currentPr.travisConfSha = commitSha;

                this._saveState();
            });
    }

    _syncBranchWithCommit (repo, owner, branchName, prSha, travisConf, prNumber) {
        if (!travisConf)
            return this.github.syncBranchWithCommit(repo, branchName, prSha);

        var temporaryBranchName = MessagesHandler._getTemporaryBranchName(branchName);
        var commitMessage       = '';

        this.github.syncBranchWithCommit(repo, temporaryBranchName, prSha)
            .then(() => this.github.getCommitMessage(repo, owner, prSha))
            .then(message => {
                commitMessage = message;

                return this.github
                    .deleteFile(repo, 'appveyor.yml', temporaryBranchName, commitMessage)
                    .catch(err => {
                        if (err.status === 'Not Found')
                            return;

                        throw err;
                    });
            })
            .then(() => {
                return this.github.replaceFile(repo, '.travis.yml', `.travis-${travisConf}.yml`,
                    temporaryBranchName, commitMessage);
            })
            .then(commitSha => {
                this.github.syncBranchWithCommit(repo, branchName, commitSha);

                var currentPr = this.state.openedPullRequests[MessagesHandler._getPRName(repo, prNumber)];

                currentPr.travisConfSha = commitSha;

                this._saveState();
            });
    }

    _getTravisConf (prTitle) {
        if (prTitle.indexOf('[docs]') > -1)
            return 'docs';

        return null;
    }

    _onPROpened (repo, prNumber, prSha, branchName, owner, title) {
        var existedPr = this.state.openedPullRequests[MessagesHandler._getPRName(repo, prNumber)];
        var pr        = existedPr || {};

        pr.number        = prNumber;
        pr.sha           = prSha;
        pr.repo          = repo;
        pr.owner         = owner;
        pr.branchName    = branchName;
        pr.travisConfSha = null;

        this.state.openedPullRequests[MessagesHandler._getPRName(repo, prNumber)] = pr;

        this._saveState();

        if (existedPr)
            this._syncBranchWithCommit(repo, owner, branchName, prSha, this._getTravisConf(title), prNumber);
        else
            this._createBranch(repo, owner, prSha, branchName, this._getTravisConf(title), prNumber);
    }

    _onPRClosed (repo, prNumber, branchName, title) {
        var prName = MessagesHandler._getPRName(repo, prNumber);
        var pr     = this.state.openedPullRequests[prName];

        clearTimeout(pr.waitForTestsTimeout);
        clearTimeout(pr.syncTimeout);

        delete this.state.openedPullRequests[prName];

        this._saveState();

        var travisConf = this._getTravisConf(title);

        this.github.deleteBranch(repo, branchName);

        if (travisConf)
            this.github.deleteBranch(repo, MessagesHandler._getTemporaryBranchName(branchName));
    }

    _waitForTestsStart (pr, repo, owner, sha, statuses) {
        var handler = this;

        if (pr.waitForTestsTimeout) {
            clearTimeout(pr.waitForTestsTimeout);
            pr.waitForTestsTimeout = null;
        }

        pr.timeToTests = Math.round(this.SYNCHRONIZE_TIMEOUT / 60000);

        function setStatus (time) {
            var message = `Tests will start in ${time} minute(s).`;

            statuses.forEach(status => (handler.collaboratorGithub ||
                handler.github).createStatus(repo, owner, sha, 'pending', '', message, status.context));

            if (time) {
                pr.waitForTestsTimeout = setTimeout(() => {
                    pr.waitForTestsTimeout = null;
                    pr.timeToTests--;

                    if (pr.timeToTests)
                        setStatus(pr.timeToTests);
                }, 60 * 1000);
            }
        }

        setStatus(pr.timeToTests);
    }

    async _onPRSynchronized (repo, prNumber, branchName, sha, owner, title) {
        var pr = this.state.openedPullRequests[MessagesHandler._getPRName(repo, prNumber)];

        if (!pr)
            return;

        var statusInfo = await this.github.getCombinedStatus(repo, this.bot.name, branchName);

        pr.sha = sha;

        if (pr.syncTimeout) {
            clearTimeout(pr.syncTimeout);
            delete pr.syncTimeout;
        }

        pr.syncTimeout = setTimeout(() => {
            delete pr.syncTimeout;
            this._saveState();

            this._syncBranchWithCommit(repo, owner, branchName, sha, this._getTravisConf(title), prNumber);
        }, this.SYNCHRONIZE_TIMEOUT);

        this._saveState();

        this._waitForTestsStart(pr, repo, owner, sha, statusInfo.statuses);
    }

    _onPRMessage (body) {
        if (/temp-pr/.test(body.pull_request.base.ref))
            return;

        var owner          = body.repository.owner.login;
        var repo           = body.repository.name;
        var prSha          = body.pull_request.head.sha;
        var prId           = body.pull_request.id;
        var title          = body.pull_request.title;
        var prNumber       = body.number;
        var testBranchName = MessagesHandler._getTestBranchName(prId);

        if (/opened/.test(body.action))
            this._onPROpened(repo, prNumber, prSha, testBranchName, owner, title);

        if (body.action === 'closed')
            this._onPRClosed(repo, prNumber, testBranchName, title);

        if (body.action === 'synchronize')
            this._onPRSynchronized(repo, prNumber, testBranchName, prSha, owner, title);
    }

    async _onStatusMessage (body) {
        log('Status message: ' + JSON.stringify(body, null, 4));

        if (body.repository.owner.login !== this.bot.name)
            return;

        var repo = body.repository.name;

        var pr = this._getPRBySha(repo, body.sha);

        if (!pr)
            return;

        var statusInfo = await this.github.getCombinedStatus(repo, this.bot.name, pr.branchName);

        if (statusInfo.sha !== body.sha)
            return;

        var owner = pr.owner;

        (this.collaboratorGithub || this.github).createStatus(repo, owner, pr.sha, body.state, body.target_url,
            body.description, body.context);

        if (statusInfo.state === 'pending' || statusInfo.statuses.some(status => status.state === 'pending'))
            return;

        var status  = statusInfo.state === 'success' ? 'passed' : 'failed';
        var mark    = MessagesHandler._getMark(statusInfo.state);
        var details = MessagesHandler._getDetails(statusInfo.statuses);

        this.github.createPullRequestComment(repo, pr.number,
            `${mark} Tests for the commit ${pr.sha} have ${status}. See ${details}.`, owner, repo);
    }

    _onIssueCommentMessage (body) {
        if (body.action !== 'created')
            return;

        var owner = body.repository.owner.login;
        var repo  = body.repository.name;
        var pr    = this.state.openedPullRequests[MessagesHandler._getPRName(repo, body.issue.number)];

        if (!pr)
            return;

        var commandHandler = this._getCommandHandler(body.comment.body, body.issue.title);

        if (!commandHandler)
            return;

        this.github.isUserCollaborator(repo, owner, body.comment.user.login)
            .then(isCollaborator => {
                if (isCollaborator)
                    commandHandler(pr);
            });
    }

    async _requestCiApi (providerType, opts) {
        return request(Object.assign({
            json:    true,
            headers: getCiApiHeaders(providerType)
        }, opts));
    }

    async _restartTravis (pr) {
        const repoSlug = encodeURIComponent(this.bot.name + '/' + pr.repo);

        const branchInfo = await this._requestCiApi(CI_PROVIDER.travis, {
            url: `https://api.travis-ci.org/repo/${repoSlug}/branch/${pr.branchName}`
        });

        const lastBuild = branchInfo['last_build'];

        const lastBuildInfo = await this._requestCiApi(CI_PROVIDER.travis, {
            url: `https://api.travis-ci.org/build/${lastBuild.id}?include=job.state`
        });

        const restartRequests = [];

        for (const job of lastBuildInfo.jobs) {
            if (job.state !== 'passed') {
                restartRequests.push(this._requestCiApi(CI_PROVIDER.travis, {
                    url:    `https://api.travis-ci.org/job/${job.id}/restart`,
                    method: 'POST'
                }));
            }
        }

        await Promise.all(restartRequests);
    }

    async _restartAppveyor (pr) {
        await this._requestCiApi(CI_PROVIDER.appveyor, {
            url:    'https://ci.appveyor.com/api/builds',
            method: 'POST',

            body: {
                accountName: this.bot.name,
                projectSlug: pr.repo,
                branch:      pr.branchName
            }
        });
    }

    async _canRestartTasks (pr, statusInfo, forceRestart) {
        if (forceRestart)
            return true;

        if (statusInfo.statuses.some(status => status.state === 'pending') || pr.syncTimeout)
            return false;

        return true;
    }

    async _restartFailedTasks (pr, { force }) {
        const statusInfo = await this.github.getCombinedStatus(pr.repo, this.bot.name, pr.branchName);

        if (!await this._canRestartTasks(pr, statusInfo, force))
            return;

        const failedStatuses = statusInfo.statuses.filter(status => status.state !== 'success');

        for (const status of failedStatuses) {
            if (status.context.startsWith('continuous-integration/appveyor'))
                await this._restartAppveyor(pr);
            else if (status.context.startsWith('continuous-integration/travis-ci'))
                await this._restartTravis(pr);
        }
    }

    async _restartAllTasks (pr, { force, title }) {
        const statusInfo = await this.github.getCombinedStatus(pr.repo, this.bot.name, pr.branchName);

        if (!await this._canRestartTasks(pr, statusInfo, force))
            return;

        this._syncBranchWithCommit(pr.repo, pr.owner, pr.branchName, pr.sha, this._getTravisConf(title), pr.number);
    }

    _getCommandHandler (message, title) {
        var name = this.bot.name;

        if (message.indexOf(`@${name}`) < 0)
            return null;

        message = message.replace(`@${name}`, '').replace(/\s/g, '').replace(/^[\/\\]/, '');

        switch (message) {
            case 'retest-all':
            case 'restart-all':
                return pr => this._restartAllTasks(pr, { title });
            case 'retest':
            case 'restart':
                return pr => this._restartFailedTasks(pr, { title });
            case 'retest-force-all':
            case 'restart-force-all':
            case 'retest-all-force':
            case 'restart-all-force':
                return pr => this._restartAllTasks(pr, { force: true, title });
            case 'retest-force':
            case 'restart-force':
                return pr => this._restartFailedTasks(pr, { force: true, title });
            default:
                return null;
        }
    }

    handle (message) {
        if (message.type === GITHUB_MESSAGE_TYPES.pullRequest)
            this._onPRMessage(message.body);

        if (message.type === GITHUB_MESSAGE_TYPES.status)
            this._onStatusMessage(message.body);

        if (message.type === GITHUB_MESSAGE_TYPES.issueComment)
            this._onIssueCommentMessage(message.body);
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012-2017, Inversoft Inc., All Rights Reserved
 *
 * 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';

/**
 * The Browser namespace. This namespace does not contain any classes, just functions.
 *
 * @namespace Browser
 */
const Browser = {
  /**
   * Detects the browser name and version.
   */
  detect: function() {
    this.name = this._searchString(this.dataBrowser) || "An unknown browser";
    this.version = this._searchVersion(navigator.userAgent) || this._searchVersion(navigator.appVersion) || "an unknown version";
    this.os = this._searchString(this.dataOS) || "an unknown OS";
  },

  /* ===================================================================================================================
   * Private Methods
   * ===================================================================================================================*/

  /**
   *
   * @param {Object} data The data array.
   * @returns {?string} The browser identity String.
   * @private
   */
  _searchString: function(data) {
    for (let i = 0; i < data.length; i++) {
      const dataString = data[i].string;
      const dataProp = data[i].prop;
      this.versionSearchString = data[i].versionSearch || data[i].identity;
      if (dataString && dataString.indexOf(data[i].subString) !== -1) {
        return data[i].identity;
      } else if (dataProp) {
        return data[i].identity;
      }
    }

    return null;
  },

  /**
   *
   * @param {string} dataString The browser data string.
   * @returns {?number} The version or null.
   * @private
   */
  _searchVersion: function(dataString) {
    const index = dataString.indexOf(this.versionSearchString);
    if (index === -1) {
      return null;
    }

    return parseFloat(dataString.substring(index + this.versionSearchString.length + 1));
  },

  dataBrowser: [
    {
      string: navigator.userAgent,
      subString: "Chrome",
      identity: "Chrome"
    },
    {
      string: navigator.userAgent,
      subString: "OmniWeb",
      versionSearch: "OmniWeb/",
      identity: "OmniWeb"
    },
    {
      string: navigator.vendor,
      subString: "Apple",
      identity: "Safari",
      versionSearch: "Version"
    },
    {
      prop: window.opera,
      identity: "Opera",
      versionSearch: "Version"
    },
    {
      string: navigator.vendor,
      subString: "iCab",
      identity: "iCab"
    },
    {
      string: navigator.vendor,
      subString: "KDE",
      identity: "Konqueror"
    },
    {
      string: navigator.userAgent,
      subString: "Firefox",
      identity: "Firefox"
    },
    {
      string: navigator.vendor,
      subString: "Camino",
      identity: "Camino"
    },
    {    // for newer Netscapes (6+)
      string: navigator.userAgent,
      subString: "Netscape",
      identity: "Netscape"
    },
    {
      string: navigator.userAgent,
      subString: "MSIE",
      identity: "Explorer",
      versionSearch: "MSIE"
    },
    {
      string: navigator.userAgent,
      subString: "Gecko",
      identity: "Mozilla",
      versionSearch: "rv"
    },
    {     // for older Netscapes (4-)
      string: navigator.userAgent,
      subString: "Mozilla",
      identity: "Netscape",
      versionSearch: "Mozilla"
    }
  ],
  dataOS: [
    {
      string: navigator.platform,
      subString: "Win",
      identity: "Windows"
    },
    {
      string: navigator.platform,
      subString: "Mac",
      identity: "Mac"
    },
    {
      string: navigator.userAgent,
      subString: "iPhone",
      identity: "iPhone/iPod"
    },
    {
      string: navigator.userAgent,
      subString: "iPad",
      identity: "iPad"
    },
    {
      string: navigator.platform,
      subString: "Linux",
      identity: "Linux"
    }
  ]
};
Browser.detect();

export {Browser}
<commit_msg>macOs<commit_after>/*
 * Copyright (c) 2012-2017, Inversoft Inc., All Rights Reserved
 *
 * 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';

/**
 * The Browser namespace. This namespace does not contain any classes, just functions.
 *
 * @namespace Browser
 */
const Browser = {
  /**
   * Detects the browser name and version.
   */
  detect: function() {
    this.name = this._searchString(this.dataBrowser) || "An unknown browser";
    this.version = this._searchVersion(navigator.userAgent) || this._searchVersion(navigator.appVersion) || "an unknown version";
    this.os = this._searchString(this.dataOS) || "an unknown OS";
  },

  /* ===================================================================================================================
   * Private Methods
   * ===================================================================================================================*/

  /**
   *
   * @param {Object} data The data array.
   * @returns {?string} The browser identity String.
   * @private
   */
  _searchString: function(data) {
    for (let i = 0; i < data.length; i++) {
      const dataString = data[i].string;
      const dataProp = data[i].prop;
      this.versionSearchString = data[i].versionSearch || data[i].identity;
      if (dataString && dataString.indexOf(data[i].subString) !== -1) {
        return data[i].identity;
      } else if (dataProp) {
        return data[i].identity;
      }
    }

    return null;
  },

  /**
   *
   * @param {string} dataString The browser data string.
   * @returns {?number} The version or null.
   * @private
   */
  _searchVersion: function(dataString) {
    const index = dataString.indexOf(this.versionSearchString);
    if (index === -1) {
      return null;
    }

    return parseFloat(dataString.substring(index + this.versionSearchString.length + 1));
  },

  dataBrowser: [
    {
      string: navigator.userAgent,
      subString: "Chrome",
      identity: "Chrome"
    },
    {
      string: navigator.userAgent,
      subString: "OmniWeb",
      versionSearch: "OmniWeb/",
      identity: "OmniWeb"
    },
    {
      string: navigator.vendor,
      subString: "Apple",
      identity: "Safari",
      versionSearch: "Version"
    },
    {
      prop: window.opera,
      identity: "Opera",
      versionSearch: "Version"
    },
    {
      string: navigator.vendor,
      subString: "iCab",
      identity: "iCab"
    },
    {
      string: navigator.vendor,
      subString: "KDE",
      identity: "Konqueror"
    },
    {
      string: navigator.userAgent,
      subString: "Firefox",
      identity: "Firefox"
    },
    {
      string: navigator.vendor,
      subString: "Camino",
      identity: "Camino"
    },
    {    // for newer Netscapes (6+)
      string: navigator.userAgent,
      subString: "Netscape",
      identity: "Netscape"
    },
    {
      string: navigator.userAgent,
      subString: "MSIE",
      identity: "Explorer",
      versionSearch: "MSIE"
    },
    {
      string: navigator.userAgent,
      subString: "Gecko",
      identity: "Mozilla",
      versionSearch: "rv"
    },
    {     // for older Netscapes (4-)
      string: navigator.userAgent,
      subString: "Mozilla",
      identity: "Netscape",
      versionSearch: "Mozilla"
    }
  ],
  dataOS: [
    {
      string: navigator.platform,
      subString: "Win",
      identity: "Windows"
    },
    {
      string: navigator.platform,
      subString: "Mac",
      identity: "macOS"
    },
    {
      string: navigator.userAgent,
      subString: "iPhone",
      identity: "iPhone/iPod"
    },
    {
      string: navigator.userAgent,
      subString: "iPad",
      identity: "iPad"
    },
    {
      string: navigator.platform,
      subString: "Linux",
      identity: "Linux"
    }
  ]
};
Browser.detect();

export {Browser}
<|endoftext|>


<commit_before>(function() {
    var bgPage = chrome.extension.getBackgroundPage();
    var player = bgPage.player;

    /*
     * Sidebar Control
     */
    $('#sidebar li').click(function() {
        $('.current').removeClass('current');

        var targetId = $(this).attr('rel');
        $(this).addClass('current');
        $('#' + targetId).addClass('current');
    });

    $('#sidebar li:first').click();

    /*
     * Player Options
     */
    $('input[name=playmode]:radio').each(function() {
        var mode = player.playmode();
        if ($(this).val() == mode)
            $(this).attr('checked', 'true')
    });

    $('input[name=playmode]:radio').click(function() {
        var mode = $(this).val();
        player.playmode(mode);
    });

    /*
     * Export / Import
     */
    exportPlaylist();
    $('#submit-import').click(importPlaylist);
    $('#refresh-export').click(exportPlaylist);

    function importPlaylist() {
        var msg = $('#import-export-page .msg');
        msg.removeClass('success error');

        var json = $('#import').val();
        var result;
        try {
            result = JSON.parse(json);
        }
        catch (error) {
            msg.addClass('error')
                .text('The imported text is not a valid JSON string.');
            return;
        }

        if (!$.isArray(result)) {
            msg.addClass('error')
                .text('The imported object is not a array of video id-title pair.');
            return;
        }

        const idPattern = /^[a-zA-Z0-9\-_]{11}$/;
        var playlist = new Array();
        for (var index = 0; index < result.length; index++)
        {
            var id = result[index].id;
            var title = result[index].title;

            if (typeof id != 'string') {
                msg.addClass('error')
                    .text('The video id "' + id + '" is not a string.');
                return;
            }
            else if (!idPattern.test(id)) {
                msg.addClass('error')
                    .text('"' + id + '" is not a valid video id.');
                return;
            }
            else if (typeof title != 'string' || title.length == 0) {
                msg.addClass('error')
                    .text('The video title is not valid.');
                return;
            }

            playlist.push({
                id: result[index].id,
                title: result[index].title
            });
        }

        player.import(playlist);
        msg.addClass('success').text('Import successful.');
    }

    function exportPlaylist() {
        var json = JSON.stringify(player.playlist);
        $('#export').val(json);
    }
})();
<commit_msg>Extract page componment of options page.<commit_after>(function() {
    var bgPage = chrome.extension.getBackgroundPage();
    var player = bgPage.player;
    var componments = {
        sidebarItems:       $('#sidebar li'),

        playmodeSelectors:  $('input[name=playmode]:radio'),

        importResultMsg:    $('#import-export-page .msg'),
        importTextarea:     $('#import'),
        importButton:       $('#submit-import'),
        exportTextarea:     $('#export'),
        exportButton:       $('#refresh-export')
    };

    /*
     * Sidebar Control
     */
    componments.sidebarItems.click(function() {
        $('.current').removeClass('current');

        var targetId = $(this).attr('rel');
        $(this).addClass('current');
        $('#' + targetId).addClass('current');
    });

    $(componments.sidebarItems[0]).click();

    /*
     * Player Options
     */
    componments.playmodeSelectors.each(function() {
        var mode = player.playmode();
        if ($(this).val() == mode)
            $(this).attr('checked', 'true')
    });

    componments.playmodeSelectors.click(function() {
        var mode = $(this).val();
        player.playmode(mode);
    });

    /*
     * Export / Import
     */
    exportPlaylist();
    componments.importButton.click(importPlaylist);
    componments.exportButton.click(exportPlaylist);

    function importPlaylist() {
        var msg = componments.importResultMsg;
        msg.removeClass('success error');

        var json = componments.importTextarea.val();
        var result;
        try {
            result = JSON.parse(json);
        }
        catch (error) {
            msg.addClass('error')
                .text('The imported text is not a valid JSON string.');
            return;
        }

        if (!$.isArray(result)) {
            msg.addClass('error')
                .text('The imported object is not a array of video id-title pair.');
            return;
        }

        const idPattern = /^[a-zA-Z0-9\-_]{11}$/;
        var playlist = new Array();
        for (var index = 0; index < result.length; index++)
        {
            var id = result[index].id;
            var title = result[index].title;

            if (typeof id != 'string') {
                msg.addClass('error')
                    .text('The video id "' + id + '" is not a string.');
                return;
            }
            else if (!idPattern.test(id)) {
                msg.addClass('error')
                    .text('"' + id + '" is not a valid video id.');
                return;
            }
            else if (typeof title != 'string' || title.length == 0) {
                msg.addClass('error')
                    .text('The video title is not valid.');
                return;
            }

            playlist.push({
                id: result[index].id,
                title: result[index].title
            });
        }

        player.import(playlist);
        msg.addClass('success').text('Import successful.');
    }

    function exportPlaylist() {
        var json = JSON.stringify(player.playlist);
        componments.exportTextarea.val(json);
    }
})();
<|endoftext|>


<commit_before>export default (debug = true) => {
	return (req, res, next) => {
		if ( ! debug) return next()

		// Log sensor data
		console.log(Date.now(), req.data.toString())
		next()
	}
}
<commit_msg>Output formatted time in debug middleware.<commit_after>export default (debug = true) => {
	return (req, res, next) => {
		if ( ! debug) return next()

		// Log sensor data
		console.log(new Date(), req.data.toString())
		next()
	}
}
<|endoftext|>


<commit_before>import ApolloClient, {createNetworkInterface} from 'apollo-client'
import {applyMiddleware} from 'redux'
import * as Actions from '../actions/ErrorHandlerAction'

const networkInterface = createNetworkInterface({
	uri: `http://${window.location.hostname}:3000/graphql`,
})

networkInterface.use([{
	applyMiddleware(req, next) {
		if (!req.options.headers) {
			req.options.headers = {}  // Create the header object if needed.
		}

		// get the authentication token from local storage if it exists
		const token = localStorage.getItem('token')
		req.options.headers.authorization = token ? `JWT ${token}` : null
		next()
	}
}]).useAfter([{
	applyAfterware({ response }, next ) {
		if (response.status !== 200) {
			client.store.dispatch(Actions.addError({key:'api_error',msg:response.status+' '+response.statusText}))
			if( response.status === 504 ){
				localStorage.removeItem('token')
			}
		}
		next()
	}
}])

export const client = new ApolloClient({
	reduxRootSelector: state => state.remote,
	networkInterface: networkInterface,
	dataIdFromObject: (o) => {
		if (o.__typename === 'KeyValue') {
			return o.__typename + o.key
		} else if (o._id) {
			return o._id
		}

		// Make sure to return null if this object doesn't have an ID
		return null
	} // will be used by Apollo Client caching
})<commit_msg>Decorator for networkInterface<commit_after>import ApolloClient, {createNetworkInterface} from 'apollo-client'
import {applyMiddleware} from 'redux'
import * as Actions from '../actions/ErrorHandlerAction'

const networkInterface = createNetworkInterface({
	uri: `http://${window.location.hostname}:3000/graphql`,
})

const logErrors = networkInterface => ({
	query: request => networkInterface.query(request).then(d => {
		// check for mongodb/graphql errors
		if( d.errors && d.errors.length ){
			client.store.dispatch(Actions.addError({key:'graphql_error',msg:d.errors[0].message}))
		}
		return d
	}).catch( e => {
		// check for server status error like 500, 504...
		client.store.dispatch(Actions.addError({key:'api_error',msg:e.message}))
		return e
	}),
	use: middlewares => networkInterface.use(middlewares)
})

const networkInterfaceDecorator = logErrors(networkInterface)

networkInterfaceDecorator.use([{
	applyMiddleware(req, next) {
		if (!req.options.headers) {
			req.options.headers = {}  // Create the header object if needed.
		}

		// get the authentication token from local storage if it exists
		const token = localStorage.getItem('token')
		req.options.headers.authorization = token ? `JWT ${token}` : null
		next()
	}
}])

export const client = new ApolloClient({
	reduxRootSelector: state => state.remote,
	networkInterface: networkInterfaceDecorator,
	dataIdFromObject: (o) => {
		if (o.__typename === 'KeyValue') {
			return o.__typename + o.key
		} else if (o._id) {
			return o._id
		}

		// Make sure to return null if this object doesn't have an ID
		return null
	} // will be used by Apollo Client caching
})<|endoftext|>


<commit_before>var requiresLogin = function(req, res, next)
{
	if(!req.session.account)
	{
		return res.redirect("/");
	}

	next();
};

var requiresLogout = function(req, res, next)
{
	if(req.session.account)
	{
		return res.redirect("/view");
	}

	next();
};

var requiresSecure = function(req, res, next)
{
	if(req.headers["x-forwarded-proto"] != "https")
	{
		return res.redirect("https://" + req.hostname + req.url);
	}

	next();
};

var bypassSecure = function(req, res, next)
{
	next();
};

module.exports.requiresLogin = requiresLogin;
module.exports.requiresLogout = requiresLogout;

if(process.env.NODE_ENV === "production")
{
	module.exports.requiresSecure = requiresSecure;
}
else
{
	module.exports.requiresSecure = bypassSecure;
}<commit_msg>Added some more debug logs<commit_after>var requiresLogin = function(req, res, next)
{
	cobnsole.log("must login");
	if(!req.session.account)
	{
		return res.redirect("/");
	}
	console.log("next");
	next();
};

var requiresLogout = function(req, res, next)
{
	console.log("must logout");
	if(req.session.account)
	{
		return res.redirect("/view");
	}
	console.log("next");
	next();
};

var requiresSecure = function(req, res, next)
{
	console.log("checking secure");
	if(req.headers["x-forwarded-proto"] != "https")
	{
		return res.redirect("https://" + req.hostname + req.url);
	}
	console.log("next");
	next();
};

var bypassSecure = function(req, res, next)
{
	console.log("no secure");
	next();
};

module.exports.requiresLogin = requiresLogin;
module.exports.requiresLogout = requiresLogout;

if(process.env.NODE_ENV === "production")
{
	module.exports.requiresSecure = requiresSecure;
}
else
{
	module.exports.requiresSecure = bypassSecure;
}<|endoftext|>


<commit_before>/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */

/**
 * Encodes a tree to a single string.
 *
 * @param {TreeNode} root
 * @return {string}
 */
var serialize = function(root) {
  const q = [root];
  const res = [];
  while (q.length) {
    const curr = q.shift();
    res.push(curr && curr.val);
    if (curr) {
      q.push(curr.left);
      q.push(curr.right);
    }
  }
  return JSON.stringify(res);
};

/**
 * Decodes your encoded data to tree.
 *
 * @param {string} data
 * @return {TreeNode}
 */
var deserialize = function(data) {
  const q = JSON.parse(data).map(val => val !== null ? new TreeNode(val) : null);
  let child = 1;
  for (var ii = 0; ii < q.length; ii++) {
    if(q[ii] !== null) {
      const left = child++;
      const right = child++;
      q[ii].left = left < q.length ? q[left] : null;
      q[ii].right = right < q.length ? q[right] : null;
    }
  }
  return q[0];
};

/**
 * Your functions will be called as such:
 * deserialize(serialize(root));
 */

function TreeNode(val) {
    this.val = val;
    this.left = this.right = null;
}

let a = new TreeNode(1);
let b = new TreeNode(2);
let c = new TreeNode(3);
let d = new TreeNode(4);
let e = new TreeNode(5);
let f = new TreeNode(6);
let g = new TreeNode(7);
let h = new TreeNode(8);
a.right = c;
c.left = b;
c.right = d;
d.right = e;
e.right = f;
f.right = g;
g.right = h;

console.log(serialize(a));
console.log(serialize(deserialize(serialize(a))));
<commit_msg>number of islands<commit_after>/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */

/**
 * Encodes a tree to a single string.
 *
 * @param {TreeNode} root
 * @return {string}
 */
var serialize = function(root) {
  const q = [root];
  const res = [];
  while (q.length) {
    const curr = q.shift();
    res.push(curr && curr.val);
    if (curr) {
      q.push(curr.left);
      q.push(curr.right);
    }
  }
  return JSON.stringify(res);
};

/**
 * Decodes your encoded data to tree.
 *
 * @param {string} data
 * @return {TreeNode}
 */
var deserialize = function(data) {
  const q = JSON.parse(data).map(val => val !== null ? new TreeNode(val) : null);
  let child = 1;
  for (var ii = 0; ii < q.length; ii++) {
    if(q[ii] !== null) {
      const left = child++;
      const right = child++;
      q[ii].left = left < q.length ? q[left] : null;
      q[ii].right = right < q.length ? q[right] : null;
    }
  }
  return q[0];
};

/**
 * Your functions will be called as such:
 * deserialize(serialize(root));
 */

function TreeNode(val) {
  this.val = val;
  this.left = this.right = null;
}

let a = new TreeNode(1);
let b = new TreeNode(2);
let c = new TreeNode(3);
let d = new TreeNode(4);
let e = new TreeNode(5);
let f = new TreeNode(6);
let g = new TreeNode(7);
let h = new TreeNode(8);
a.right = c;
c.left = b;
c.right = d;
d.right = e;
e.right = f;
f.right = g;
g.right = h;

console.log(serialize(a));
console.log(serialize(deserialize(serialize(a))));
<|endoftext|>


<commit_before>/*
Copyright (C) 2016  Eugene Lockett  gene@noonian.org

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * datasource/packaging
 * @module db._svc.PackagingService
 *
 * Contains logic for building, installing, and versioning noonian packages.
 *
 */
'use strict';

var Q = require('q');
var _ = require('lodash');

var fs = require('fs');

var serverConf = require('../../../conf');

var db = require('../index');

var GridFsService = require('../gridfs');
var DataTriggerService = require('../datatrigger');

var VersionId = exports.VersionId = require('../version_id');

var fsPackageSyncer = require('./fs_sync');
var packageStreamer = require('./pkg_stream');

exports.buildPackage = packageStreamer.buildPackage;
exports.applyPackageStream = exports.installPackageStream = packageStreamer.installPackage;

var diffTool = require('./diffpatch');

/*
 * pkgConfig holds an array of pacakge configuration objects:
   {
     key:"package key",
     enableFilesystemSync:true,
     fs_path:"path of package files - absolute or relative to noonian base",
     include:{lookup table - classes explicitly included in this package},
     exclude:{lookup table - classes to exclude from this package}
   }
 */
var pkgConfig;
var packageKeyToId; //to look-up BOP id with package key
var packageKeyToConfig;

var updatePackageConfig = function() {

    //Sync up w/ package meta if it belongs to an fs-synced package
    var THIS = this;
    _.forEach(pkgConfig, function(p) {
        if(p.enableFilesystemSync && p.key === THIS.key) {
            fsPackageSyncer.writeMetaFile(p.fs_path, THIS);
        }
    });

    return db.BusinessObjectPackage.find({}).then(function(bopList) {

        var fsConfig = serverConf.packageFsConfig || {};

        packageKeyToId = {};//Build up BOP key->id map
        packageKeyToConfig = {}; //and one for the Config
        pkgConfig = [];

        _.forEach(bopList, function(bop) {
            packageKeyToId[bop.key] = bop._id;

            if(bop.enable_building || fsConfig[bop.key]) {
                var cfg = {key:bop.key, _id:bop._id};
                pkgConfig.push(cfg);
                packageKeyToConfig[bop.key] = cfg;

                var bConfig = bop.build_config || {};
                var fsPath = fsConfig[bop.key]

                if(fsPath) {
                    cfg.enableFilesystemSync = true;
                    cfg.fs_path = (typeof fsPath === 'string') ? fsPath : 'server/data_pkg/'+bop.key;
                }
                if(bConfig.include) {
                    cfg.include = _.mapKeys(bConfig.include);
                }
                if(bConfig.exclude) {
                    cfg.exclude = _.mapKeys(bConfig.exclude);
                }
            }
        }); //end forEach(bopList)
        console.log('CURRENT PACKAGE CONFIG: %j', pkgConfig);
    });
};

/**
 * Initialize the package-builder logic: data trigger, etc.
 **/
exports.init = function() {
    console.log('Initializing packaging service');

    var promiseChain = Q(true);

    //Load in fs-persisted packages as configured in serverConf.packageFsConfig
    _.forEach(serverConf.packageFsConfig, function(fsPath, pkgKey) {
        console.log('...loading %s from filesystem...', pkgKey);
        promiseChain = promiseChain.then(fsPackageSyncer.packageFromFs.bind(null, fsPath));
    });

    //Build up aggregate packageConf by merging in configurations from BusinessObjectPackages
    promiseChain = promiseChain
    .then(updatePackageConfig)
    .then(function() {

        //Register UpdateLogger datatrigger
        DataTriggerService.registerDataTrigger(
            'sys.internal.update_logger',
            null,               //any BO class
            'after',            //'after' change is persisted to DB
            true,               //on create
            true,               //on update
            true,               //on delete
            exports.updateLogger  //the handler
        );

        //Register DT to keep pkgConfig in sync w/ BusinessObjectPackage's in the db
        DataTriggerService.registerDataTrigger(
            'sys.internal.business_object_package',
            'QLN_PHr_Tj6nzgzrHA4XdQ',   //BusinessObjectPackage
            'after',            //'after' change is persisted to DB
            true,               //on create
            true,               //on update
            true,               //on delete
            updatePackageConfig  //the handler
        );

    })
    ;

    return promiseChain;
}; //end init()

/**
 * When any update happens in the system, create an UpdateLog object, which tracks:
 *   timestamp, updated object, version updated, diff patch (apply to updated version to revert),
 *   and package reference
 */
 var ignoreClasses = {
    BusinessObjectPackage:true,
    UpdateLog:true
};

exports.updateLogger = function(isCreate, isUpdate, isDelete) {
    var myClass = this._bo_meta_data.class_name;

    if(ignoreClasses[myClass]) {
        return;
    }

    if(!db.UpdateLog) {
        return console.error('missing UpdateLog business object.  System upgrade required.');
    }

    var updateType = isCreate ? 'create' : (isUpdate ? 'update' : 'delete');

    console.log('updateLogger: %s for %j', updateType, this);

    var updateLogObj = new db.UpdateLog({
       timestamp: new Date(),
       object_class: myClass,
       object_id: this._id,
       update_type:updateType
    });

    if(!isCreate) {
        updateLogObj.updated_version = this._previous.__ver;

        if(serverConf.enableHistory) {
            if(isDelete) {
                updateLogObj.revert_patch = this._previous;
            }
            else {
                //its an update; store the diff
                //  want to be able to take it from current -> previous
                // (diffTool configured to ignore properties starting w/ underscore)
                var current = this;
                var previous = this._previous;
                //TODO DOESNT WORK FOR OBJECTS W/ FUNCTION FIELDS!  NEED TO CONVERT TO STRING FIRST!!!
                updateLogObj.revert_patch = diffTool.diff(current.toPlainObject(), previous);
            }
        }
    }

    var targetPkg;

    if(serverConf.enablePackaging) {
        console.log('processing packaging!');
        //Determine the package to which this updateLog is attached.

        _.forEach(pkgConfig, function(p) {
            if(p.exclude && p.exclude[myClass]) {
                return;
            }
            if(p.include && !p.include[myClass]) {
                return;
            }
            //Use the first one on the list that matches
            targetPkg = targetPkg || p;
        });
        console.log('targetPkg: %j', targetPkg);

        if(targetPkg) {
            //Set a special flag if a BO belonging to a different "external"
            // package is incorporated into another package
            updateLogObj.external_pkg = !!(this.__pkg && this.__pkg !== targetPkg.key);

            //Declare "ownership" of this BO if it hasn't already been declared
            this.__pkg = this.__pkg || targetPkg.key;

            //Link this update to the configured package
            updateLogObj.package = {_id:targetPkg._id};

            //Persist update to filesystem if configured to do so
            if(targetPkg.enableFilesystemSync) {
               if(!isDelete) {
                   fsPackageSyncer.writeObjectToPackageDir(targetPkg.fs_path, this);
               }
               else {
                   fsPackageSyncer.removeObjectFromPackageDir(targetPkg.fs_path, this);
               }
           }
        }
        else if(this.__pkg) {
            //pacakging is not explicitly configured for this change,
            // but the BO has an "owner" package, so let's tie it to the UpdateLog
            var ownerPkgId = packageKeyToId[this.__pkg];
            if(ownerPkgId) {
                updateLogObj.package = {_id:ownerPkgId};
            }
            else {
                console.warn('Owning package %s missing from this system (owned by %s.%s', this.__pkg, myClass, this._id);
            }
        }
    }

    var retPromise = updateLogObj.save({skipTriggers:true});

    /*
     * We want to persist the UpdateLog object so that the package can be built
     * on an instance populated from the objects on the filesystem.
     * Objects belonging to the package are enumerated in the manifest,
     * so we only need to keep track of creates and deletes
     *
     */
    if(targetPkg && targetPkg.enableFilesystemSync) {  //we're syncing to the filesystem
        if(!isUpdate || serverConf.enableHistory) {
            // its either a create or delete OR we want to save all history
            retPromise = retPromise.then(function(logObj) {
                fsPackageSyncer.writeObjectToPackageDir(targetPkg.fs_path, logObj);
            });
        }
    }

    return retPromise;
};

/**
 * Apply package attached to a BusinessObjectPackage
 */
exports.applyPackage = function(bopId) {
  var bopObj;
  return db.BusinessObjectPackage.findOne({_id:bopId})
    .then(function(bop) {
      bopObj = bop;

      if(!bop || !bop.package_file || !bop.package_file.attachment_id) {
        throw 'Invalid BusinessObjectPackage';
      }
      else {
        return GridFsService.getFile(bop.package_file.attachment_id)
      }
    })
    .then(function(gridfsFileObj) {
      console.log('Loading Data Package from %s', gridfsFileObj.metadata.filename);
      return packageStreamer.installPackage(gridfsFileObj.readstream).then(function(retBop) {
        bopObj = retBop;
      });
    })
    .then(db._svc.RefService.repair)
    .then(function() {
      return bopObj.key;
    });

};

/**
 * - searches local PKG_DIR for package w/ pkgName
 * - applies latest version it finds
 **/
var PKG_DIR = 'server/data_pkg';
exports.applyLocalPackage = function(pkgName) {

  // var deferred = Q.defer();

  var pkgFiles = fs.readdirSync(PKG_DIR);

  var fileRegex = new RegExp(pkgName+'\\.(\\d+)\\.(\\d+)\\.json');

  var foundFilename;
  var maj=-1, min=-1;

  _.forEach(pkgFiles, function(filename) {
    var match = fileRegex.exec(filename);
    if(match) {
      var testMaj = +match[1];
      var testMin = +match[2];
      if(testMaj > maj || (testMaj == maj && testMin > min) ) {
        foundFilename = filename;
        maj = testMaj;
        min = testMin;
      }
    }
  });
  console.log('Loading local package file %s (version %s.%s)', foundFilename, maj, min);

  var readstream = fs.createReadStream(PKG_DIR+'/'+foundFilename);

  return packageStreamer.installPackage(readstream);

};

/**
 * importObject
 * Import a plain json object (originating from a package or file) into db
 * With special handling of BusinessObjectDef's and versioning.
 *
 * used by both fs_sync and pkg_stream
 *
 * @param className
 * @param obj JSON object
 * @param pacakgeRef - reference to BusinessObjectPackage on who's behalf this object is being imported;
 *                     if not present, no version checking will occur
 */
exports.importObject = function(className, obj, packageRef) {
    var boId = obj._id;

    if(!db[className]) {
        //May happen if installing a package who's dependencies aren't installed
        if(!packageRef || ! db.PackageConflict) {
            throw new Error('missing class '+className);
        }
        //Flag the problem via a PackageConflict
        var conflictObj = new db.PackageConflict({
            package:packageRef,
            conflict_type:'missing class',
            object_class:className,
            object_id:boId,
            package_version_id:obj.__ver,
            merged_object:obj
        });
        return conflictObj.save();
    }

    return db[className].findOne({_id:boId}).then(function(modelObj) {

        if(packageRef && modelObj && db.PackageConflict) {

            //Check validity of stepping from current version -> update version
            var updateVer = obj.__ver;

            var currentVer = new VersionId(modelObj.__ver);
            var pkgVer = new VersionId(updateVer);
            var versionRel = pkgVer.relationshipTo(currentVer);

            if(versionRel.same) {
                //If they're the same
                if(className === 'BusinessObjectDef') {
                    //Special case: always refresh BOD's w/ system datalayer
                    return db.installBusinessObjectDef(obj);
                }
                else {
                    return;
                }
            }

            if(!versionRel.descendant) {
                //update is not a decendent of currentVer, raise a flag
                var conflictObj = new db.PackageConflict({
                    package:packageRef,
                    object_class:className,
                    object_id:boId,
                    installed_version_id:modelObj.__ver,
                    package_version_id:updateVer
                });

                if(versionRel.cousin) {
                    conflictObj.conflict_type = 'divergent';
                    //incorporate all data needed to perform a merge
                    conflictObj.installed_object = modelObj.toPlainObject();
                    conflictObj.merged_object = obj;
                    //diff from installed -> package version
                    conflictObj.diff = diffTool.diff(conflictObj.installed_object, conflictObj.merged_object);
                }
                else {
                    conflictObj.conflict_type = 'independent update';
                    //installed one is actually newer; diff serves to highlight the local changes made to the package version
                    conflictObj.diff = diffTool.diff(obj, modelObj.toPlainObject());
                }

                return conflictObj.save();
            }
        }

        if(className === 'BusinessObjectDef') {
            return db.installBusinessObjectDef(obj);
        }

        var updateVer = obj.__ver;
        delete obj.__ver;

        if(!modelObj) {
            modelObj = new db[className](obj);
        }
        else {
            _.assign(modelObj, obj);
        }

        return modelObj.save({useVersionId:updateVer, skipTriggers:true}, null);

    });

};

/**
 * Exports a package's objects to filesystem, to begin filesystem sync and allow for
 * collaboration/source control in git
 */
exports.packageToFs = function(bopId) {
    var bopObj;
  return db.BusinessObjectPackage.findOne({_id:bopId})
    .then(function(bop) {
      bopObj = bop;

      if(!bop) {
        throw 'Invalid BusinessObjectPackage';
      }
      else {
          var cfg = packageKeyToConfig[bop.key];
          if(!cfg || !cfg.fs_path) {
              throw 'Filesystem sync not configured for '+bop.key+'. Please set packageFsConfig in instance config.';
          }

          return fsPackageSyncer.packageObjectsToFs(bop, cfg.fs_path);
      }
    });
}

/**
 * Convenience function to drop the full package json file (attached to BOP) into data_pkg directory.
 **/
exports.packageFileExport = function(bopId) {
  var bopObj;
  return db.BusinessObjectPackage.findOne({_id:bopId})
    .then(function(bop) {
      bopObj = bop;

      if(!bop) {
        throw 'Invalid BusinessObjectPackage';
      }
      else if(singleFile && (!bop.package_file || !bop.package_file.attachment_id) ){
        throw 'Missing package_file';
      }
      else {
        return GridFsService.getFile(bop.package_file.attachment_id).then(function(gridfsFileObj) {
          console.log('Exporting package %s to data_pkg on filesystem', gridfsFileObj.metadata.filename);

          var outputFile = fs.createWriteStream(PKG_DIR+'/'+gridfsFileObj.metadata.filename);
          return gridfsFileObj.readstream.pipe(outputFile);

        });
      }
    });
};

exports.parseVersionString = function(verStr) {
  var major = 0;
  var minor = 0;

  if(verStr) {
    var dotPos = verStr.indexOf('.');
    if(dotPos > -1) {
      major = +(verStr.substring(0, dotPos));
      minor = +(verStr.substring(dotPos+1));
    }
    else {
      minor = +verStr;
    }
  }

  return new packageStreamer.PkgVersion(major, minor);
};

<commit_msg>ignore PackageConflict's for updatelog processing<commit_after>/*
Copyright (C) 2016  Eugene Lockett  gene@noonian.org

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * datasource/packaging
 * @module db._svc.PackagingService
 *
 * Contains logic for building, installing, and versioning noonian packages.
 *
 */
'use strict';

var Q = require('q');
var _ = require('lodash');

var fs = require('fs');

var serverConf = require('../../../conf');

var db = require('../index');

var GridFsService = require('../gridfs');
var DataTriggerService = require('../datatrigger');

var VersionId = exports.VersionId = require('../version_id');

var fsPackageSyncer = require('./fs_sync');
var packageStreamer = require('./pkg_stream');

exports.buildPackage = packageStreamer.buildPackage;
exports.applyPackageStream = exports.installPackageStream = packageStreamer.installPackage;

var diffTool = require('./diffpatch');

/*
 * pkgConfig holds an array of pacakge configuration objects:
   {
     key:"package key",
     enableFilesystemSync:true,
     fs_path:"path of package files - absolute or relative to noonian base",
     include:{lookup table - classes explicitly included in this package},
     exclude:{lookup table - classes to exclude from this package}
   }
 */
var pkgConfig;
var packageKeyToId; //to look-up BOP id with package key
var packageKeyToConfig;

var updatePackageConfig = function() {

    //Sync up w/ package meta if it belongs to an fs-synced package
    var THIS = this;
    _.forEach(pkgConfig, function(p) {
        if(p.enableFilesystemSync && p.key === THIS.key) {
            fsPackageSyncer.writeMetaFile(p.fs_path, THIS);
        }
    });

    return db.BusinessObjectPackage.find({}).then(function(bopList) {

        var fsConfig = serverConf.packageFsConfig || {};

        packageKeyToId = {};//Build up BOP key->id map
        packageKeyToConfig = {}; //and one for the Config
        pkgConfig = [];

        _.forEach(bopList, function(bop) {
            packageKeyToId[bop.key] = bop._id;

            if(bop.enable_building || fsConfig[bop.key]) {
                var cfg = {key:bop.key, _id:bop._id};
                pkgConfig.push(cfg);
                packageKeyToConfig[bop.key] = cfg;

                var bConfig = bop.build_config || {};
                var fsPath = fsConfig[bop.key]

                if(fsPath) {
                    cfg.enableFilesystemSync = true;
                    cfg.fs_path = (typeof fsPath === 'string') ? fsPath : 'server/data_pkg/'+bop.key;
                }
                if(bConfig.include) {
                    cfg.include = _.mapKeys(bConfig.include);
                }
                if(bConfig.exclude) {
                    cfg.exclude = _.mapKeys(bConfig.exclude);
                }
            }
        }); //end forEach(bopList)
        console.log('CURRENT PACKAGE CONFIG: %j', pkgConfig);
    });
};

/**
 * Initialize the package-builder logic: data trigger, etc.
 **/
exports.init = function() {
    console.log('Initializing packaging service');

    var promiseChain = Q(true);

    //Load in fs-persisted packages as configured in serverConf.packageFsConfig
    _.forEach(serverConf.packageFsConfig, function(fsPath, pkgKey) {
        console.log('...loading %s from filesystem...', pkgKey);
        promiseChain = promiseChain.then(fsPackageSyncer.packageFromFs.bind(null, fsPath));
    });

    //Build up aggregate packageConf by merging in configurations from BusinessObjectPackages
    promiseChain = promiseChain
    .then(updatePackageConfig)
    .then(function() {

        //Register UpdateLogger datatrigger
        DataTriggerService.registerDataTrigger(
            'sys.internal.update_logger',
            null,               //any BO class
            'after',            //'after' change is persisted to DB
            true,               //on create
            true,               //on update
            true,               //on delete
            exports.updateLogger  //the handler
        );

        //Register DT to keep pkgConfig in sync w/ BusinessObjectPackage's in the db
        DataTriggerService.registerDataTrigger(
            'sys.internal.business_object_package',
            'QLN_PHr_Tj6nzgzrHA4XdQ',   //BusinessObjectPackage
            'after',            //'after' change is persisted to DB
            true,               //on create
            true,               //on update
            true,               //on delete
            updatePackageConfig  //the handler
        );

    })
    ;

    return promiseChain;
}; //end init()

/**
 * When any update happens in the system, create an UpdateLog object, which tracks:
 *   timestamp, updated object, version updated, diff patch (apply to updated version to revert),
 *   and package reference
 */
 var ignoreClasses = {
    BusinessObjectPackage:true,
    UpdateLog:true,
    PackageConflict:true
};

exports.updateLogger = function(isCreate, isUpdate, isDelete) {
    var myClass = this._bo_meta_data.class_name;

    if(ignoreClasses[myClass]) {
        return;
    }

    if(!db.UpdateLog) {
        return console.error('missing UpdateLog business object.  System upgrade required.');
    }

    var updateType = isCreate ? 'create' : (isUpdate ? 'update' : 'delete');

    console.log('updateLogger: %s for %j', updateType, this);

    var updateLogObj = new db.UpdateLog({
       timestamp: new Date(),
       object_class: myClass,
       object_id: this._id,
       update_type:updateType
    });

    if(!isCreate) {
        updateLogObj.updated_version = this._previous.__ver;

        if(serverConf.enableHistory) {
            if(isDelete) {
                updateLogObj.revert_patch = this._previous;
            }
            else {
                //its an update; store the diff
                //  want to be able to take it from current -> previous
                // (diffTool configured to ignore properties starting w/ underscore)
                var current = this;
                var previous = this._previous;
                //TODO DOESNT WORK FOR OBJECTS W/ FUNCTION FIELDS!  NEED TO CONVERT TO STRING FIRST!!!
                updateLogObj.revert_patch = diffTool.diff(current.toPlainObject(), previous);
            }
        }
    }

    var targetPkg;

    if(serverConf.enablePackaging) {
        console.log('processing packaging!');
        //Determine the package to which this updateLog is attached.

        _.forEach(pkgConfig, function(p) {
            if(p.exclude && p.exclude[myClass]) {
                return;
            }
            if(p.include && !p.include[myClass]) {
                return;
            }
            //Use the first one on the list that matches
            targetPkg = targetPkg || p;
        });
        console.log('targetPkg: %j', targetPkg);

        if(targetPkg) {
            //Set a special flag if a BO belonging to a different "external"
            // package is incorporated into another package
            updateLogObj.external_pkg = !!(this.__pkg && this.__pkg !== targetPkg.key);

            //Declare "ownership" of this BO if it hasn't already been declared
            this.__pkg = this.__pkg || targetPkg.key;

            //Link this update to the configured package
            updateLogObj.package = {_id:targetPkg._id};

            //Persist update to filesystem if configured to do so
            if(targetPkg.enableFilesystemSync) {
               if(!isDelete) {
                   fsPackageSyncer.writeObjectToPackageDir(targetPkg.fs_path, this);
               }
               else {
                   fsPackageSyncer.removeObjectFromPackageDir(targetPkg.fs_path, this);
               }
           }
        }
        else if(this.__pkg) {
            //pacakging is not explicitly configured for this change,
            // but the BO has an "owner" package, so let's tie it to the UpdateLog
            var ownerPkgId = packageKeyToId[this.__pkg];
            if(ownerPkgId) {
                updateLogObj.package = {_id:ownerPkgId};
            }
            else {
                console.warn('Owning package %s missing from this system (owned by %s.%s', this.__pkg, myClass, this._id);
            }
        }
    }

    var retPromise = updateLogObj.save({skipTriggers:true});

    /*
     * We want to persist the UpdateLog object so that the package can be built
     * on an instance populated from the objects on the filesystem.
     * Objects belonging to the package are enumerated in the manifest,
     * so we only need to keep track of creates and deletes
     *
     */
    if(targetPkg && targetPkg.enableFilesystemSync) {  //we're syncing to the filesystem
        if(!isUpdate || serverConf.enableHistory) {
            // its either a create or delete OR we want to save all history
            retPromise = retPromise.then(function(logObj) {
                fsPackageSyncer.writeObjectToPackageDir(targetPkg.fs_path, logObj);
            });
        }
    }

    return retPromise;
};

/**
 * Apply package attached to a BusinessObjectPackage
 */
exports.applyPackage = function(bopId) {
  var bopObj;
  return db.BusinessObjectPackage.findOne({_id:bopId})
    .then(function(bop) {
      bopObj = bop;

      if(!bop || !bop.package_file || !bop.package_file.attachment_id) {
        throw 'Invalid BusinessObjectPackage';
      }
      else {
        return GridFsService.getFile(bop.package_file.attachment_id)
      }
    })
    .then(function(gridfsFileObj) {
      console.log('Loading Data Package from %s', gridfsFileObj.metadata.filename);
      return packageStreamer.installPackage(gridfsFileObj.readstream).then(function(retBop) {
        bopObj = retBop;
      });
    })
    .then(db._svc.RefService.repair)
    .then(function() {
      return bopObj.key;
    });

};

/**
 * - searches local PKG_DIR for package w/ pkgName
 * - applies latest version it finds
 **/
var PKG_DIR = 'server/data_pkg';
exports.applyLocalPackage = function(pkgName) {

  // var deferred = Q.defer();

  var pkgFiles = fs.readdirSync(PKG_DIR);

  var fileRegex = new RegExp(pkgName+'\\.(\\d+)\\.(\\d+)\\.json');

  var foundFilename;
  var maj=-1, min=-1;

  _.forEach(pkgFiles, function(filename) {
    var match = fileRegex.exec(filename);
    if(match) {
      var testMaj = +match[1];
      var testMin = +match[2];
      if(testMaj > maj || (testMaj == maj && testMin > min) ) {
        foundFilename = filename;
        maj = testMaj;
        min = testMin;
      }
    }
  });
  console.log('Loading local package file %s (version %s.%s)', foundFilename, maj, min);

  var readstream = fs.createReadStream(PKG_DIR+'/'+foundFilename);

  return packageStreamer.installPackage(readstream);

};

/**
 * importObject
 * Import a plain json object (originating from a package or file) into db
 * With special handling of BusinessObjectDef's and versioning.
 *
 * used by both fs_sync and pkg_stream
 *
 * @param className
 * @param obj JSON object
 * @param pacakgeRef - reference to BusinessObjectPackage on who's behalf this object is being imported;
 *                     if not present, no version checking will occur
 */
exports.importObject = function(className, obj, packageRef) {
    var boId = obj._id;

    if(!db[className]) {
        //May happen if installing a package who's dependencies aren't installed
        if(!packageRef || ! db.PackageConflict) {
            throw new Error('missing class '+className);
        }
        //Flag the problem via a PackageConflict
        var conflictObj = new db.PackageConflict({
            package:packageRef,
            conflict_type:'missing class',
            object_class:className,
            object_id:boId,
            package_version_id:obj.__ver,
            merged_object:obj
        });
        return conflictObj.save();
    }

    return db[className].findOne({_id:boId}).then(function(modelObj) {

        if(packageRef && modelObj && db.PackageConflict) {

            //Check validity of stepping from current version -> update version
            var updateVer = obj.__ver;

            var currentVer = new VersionId(modelObj.__ver);
            var pkgVer = new VersionId(updateVer);
            var versionRel = pkgVer.relationshipTo(currentVer);

            if(versionRel.same) {
                //If they're the same
                if(className === 'BusinessObjectDef') {
                    //Special case: always refresh BOD's w/ system datalayer
                    return db.installBusinessObjectDef(obj);
                }
                else {
                    return;
                }
            }

            if(!versionRel.descendant) {
                //update is not a decendent of currentVer, raise a flag
                var conflictObj = new db.PackageConflict({
                    package:packageRef,
                    object_class:className,
                    object_id:boId,
                    installed_version_id:modelObj.__ver,
                    package_version_id:updateVer
                });

                if(versionRel.cousin) {
                    conflictObj.conflict_type = 'divergent';
                    //incorporate all data needed to perform a merge
                    conflictObj.installed_object = modelObj.toPlainObject();
                    conflictObj.merged_object = obj;
                    //diff from installed -> package version
                    conflictObj.diff = diffTool.diff(conflictObj.installed_object, conflictObj.merged_object);
                }
                else {
                    conflictObj.conflict_type = 'independent update';
                    //installed one is actually newer; diff serves to highlight the local changes made to the package version
                    conflictObj.diff = diffTool.diff(obj, modelObj.toPlainObject());
                }

                return conflictObj.save();
            }
        }

        if(className === 'BusinessObjectDef') {
            return db.installBusinessObjectDef(obj);
        }

        var updateVer = obj.__ver;
        delete obj.__ver;

        if(!modelObj) {
            modelObj = new db[className](obj);
        }
        else {
            _.assign(modelObj, obj);
        }

        return modelObj.save({useVersionId:updateVer, skipTriggers:true}, null);

    });

};

/**
 * Exports a package's objects to filesystem, to begin filesystem sync and allow for
 * collaboration/source control in git
 */
exports.packageToFs = function(bopId) {
    var bopObj;
  return db.BusinessObjectPackage.findOne({_id:bopId})
    .then(function(bop) {
      bopObj = bop;

      if(!bop) {
        throw 'Invalid BusinessObjectPackage';
      }
      else {
          var cfg = packageKeyToConfig[bop.key];
          if(!cfg || !cfg.fs_path) {
              throw 'Filesystem sync not configured for '+bop.key+'. Please set packageFsConfig in instance config.';
          }

          return fsPackageSyncer.packageObjectsToFs(bop, cfg.fs_path);
      }
    });
}

/**
 * Convenience function to drop the full package json file (attached to BOP) into data_pkg directory.
 **/
exports.packageFileExport = function(bopId) {
  var bopObj;
  return db.BusinessObjectPackage.findOne({_id:bopId})
    .then(function(bop) {
      bopObj = bop;

      if(!bop) {
        throw 'Invalid BusinessObjectPackage';
      }
      else if(singleFile && (!bop.package_file || !bop.package_file.attachment_id) ){
        throw 'Missing package_file';
      }
      else {
        return GridFsService.getFile(bop.package_file.attachment_id).then(function(gridfsFileObj) {
          console.log('Exporting package %s to data_pkg on filesystem', gridfsFileObj.metadata.filename);

          var outputFile = fs.createWriteStream(PKG_DIR+'/'+gridfsFileObj.metadata.filename);
          return gridfsFileObj.readstream.pipe(outputFile);

        });
      }
    });
};

exports.parseVersionString = function(verStr) {
  var major = 0;
  var minor = 0;

  if(verStr) {
    var dotPos = verStr.indexOf('.');
    if(dotPos > -1) {
      major = +(verStr.substring(0, dotPos));
      minor = +(verStr.substring(dotPos+1));
    }
    else {
      minor = +verStr;
    }
  }

  return new packageStreamer.PkgVersion(major, minor);
};

<|endoftext|>


<commit_before>'use strict';

module.exports = function (app) {
  //jshint unused: false
  //noinspection JSUnusedLocalSymbols
  app.use(function (err, req, res, next) {
    var status = err.status || 500;
    if (status === 500) {
      console.error(err.stack);
    }
    res.status(status);
    res.send({
      status: status,
      message: err.message,
      code: err.code
    });
  });
};

<commit_msg>Server: ValidationError handling added.<commit_after>'use strict';

module.exports = function (app) {
  //jshint unused: false
  //noinspection JSUnusedLocalSymbols
  app.use(function (err, req, res, next) {
    if (err.name === 'ValidationError') {
      res.status(400).json(err);
    } else {
      var status = err.status || 500;
      if (status === 500) {
        console.error(err.stack);
      }
      res.status(status).send({
        status: status,
        message: err.message,
        code: err.code
      });
    }
  });
};

<|endoftext|>


<commit_before>(function (messagesController) {

    messagesController.init = function (app, logWriter) {

        var manager = require("common/managers/messagesManager");
        manager.init(logWriter)

        app.get("/messages/:category", function (req, res) {

            var category = req.params.category;

            logWriter.write("debug", "Getting messages with category: " + category + "...");

            var messages = manager.getGlobalMessages();

            res.send(messages);
        });

    }

})(module.exports)<commit_msg>Checked category is one of the expected ones<commit_after>(function (messagesController) {

    messagesController.init = function (app, logWriter) {

        var manager = require("common/managers/messagesManager");
        manager.init(logWriter)

        app.get("/messages/:category", function (req, res) {

            var category = req.params.category.toLowerCase();

            logWriter.write("debug", "Getting messages with category '" + category + "'...");

            switch (category) {
                case "global":
                    var messages = manager.getGlobalMessages();
                    break;
                case "group":
                case "private":
                    break;
                default:
                    var errorMessage = "Category '" + category + "' not supported";
                    logWriter.write("warning", errorMessage);
                    res.send(errorMessage);
                    return;
            }

            res.send(messages);
        });

    }

})(module.exports)<|endoftext|>