<commit_before>/****************************************************************************
 * PrettyPrintHTML5ROCKS
 * This is the script which modifies the articles on
 * http://www.html5rocks.com and make them fit for printing.
 * Author:Ishan
 * email: ishanatmuzaffarpur@gmail.com
 * Google Plus: https://plus.google.com/111814328368711145786
 ****************************************************************************/

/* Steps:
  1. Rmove the top header of the page.
  2. Remove the Table of Contents.
  3. Fill the extra space by the article content.
  4. Resize the Code Snippets
  5. Remove the number of comments.
  6. Add the URL to bottom of the article.
  7. Remove the disqus comments.
  8. Remove the footer
  9. If there are embedded videos remove them.
 10. If there is redirect message remove it.
 11. Call window.print() to print the document.
*/

/******************************************************
 *     Step By Step Code
 ******************************************************/

// jsLint global variables
/*jslint browser: true, devel: true */

// Current Working set

// Global variables
var pageMode, urlMode;
var embeds, ref, codeSnippets;
var i;
var urlHolder, redirectMessage;
var articleFontSize = '12px', codeSnippetsFontSize = '10px';
var ARTICLEFONTSIZEORIGINAL = '18px', CODESNIPPETSFONTSIZEORIGINAL = '15px';

if (location.href.substring(0, 30) === "http://updates.html5rocks.com/" || location.href.substring(0, 26) === "http://www.html5rocks.com/") {
    // Breaking URL into parts
    var partsOfURL = location.href.split('/');

    if (partsOfURL[4] === "tutorials" && partsOfURL[6] !== undefined) {

        var articleModifier = function () {
            'use strict';
            // html5rocks->tutorial

            // switching between print and web display
            // document.getElementsByTagName('header')[0].style.display
            // Defaults to 'false' in the first run.
            // element.style doesn't get computed styles it gets set styles
            // instead use window.getComputedStyle(element)
            // referred from here http://stackoverflow.com/questions/20329730/
            if (window.getComputedStyle(document.getElementsByTagName('header')[0]).display === 'none') {
                pageMode = 'block';
                urlMode = 'none';
            } else {
                pageMode = 'none';
                urlMode = 'block';
            }

            // Remove top header
            document.getElementsByTagName('header')[0].style.display = pageMode;

            // selecting divs so that further elements of the page can be selected
            var divs = document.getElementsByTagName('div');

            // Hide Table of Contents
            divs[1].style.display = pageMode;

            // switching the article between print mode and web mode
            if (pageMode === 'none') {
                // Making article fill the screen
                divs[2].style.marginLeft = '0px';
                divs[2].style.maxWidth = 'inherit';
                divs[2].style.width = '100%';
                // Making text small
                divs[2].style.fontSize = articleFontSize;
                // Reduce the line-height
                divs[2].style.lineHeight = 1.0;
            } else {
                // Making article shrink back
                divs[2].style.marginLeft = '350px';
                divs[2].style.maxWidth = '660px';
                divs[2].style.width = '87%';
                //Enlarging the text again
                divs[2].style.fontSize = ARTICLEFONTSIZEORIGINAL;
                // Reset the line-height
                divs[2].style.lineHeight = 1.5;
            }

            // Resizng the code snippets
            codeSnippets = document.getElementsByClassName('prettyprint');
            if (pageMode === 'none') {
                for (i = codeSnippets.length - 1; i >= 0; i = i - 1) {
                    codeSnippets[i].style.fontSize = codeSnippetsFontSize;
                }
            } else {
                for (i = codeSnippets.length - 1; i >= 0; i = i - 1) {
                    codeSnippets[i].style.fontSize = CODESNIPPETSFONTSIZEORIGINAL;
                }
            }

            // Remove the number of comments
            document.getElementsByClassName('load-comments')[0].parentElement.style.display = pageMode;

            // Creating URL Holder if it is not deifned
            if (typeof (urlHolder) === 'undefined') {
                // Create a new element for the URL
                urlHolder = document.createElement('section');
                // make it look like it belongs
                urlHolder.className = 'cc pattern-bg-lighter';
                // append it after the article
                divs[2].appendChild(urlHolder);

                // Set innerText to the url
                urlHolder.innerText = location.href;
                // Stylising the reference
                urlHolder.style.marginLeft = '0px';
                urlHolder.style.textAlign = 'center';
                urlHolder.style.fontWeight = 'bold';
                urlHolder.style.paddingTop = '20px';
            }

            // switching display of disqus comments for print mode and web mode
            document.getElementById('disqus').style.display = pageMode;

            // switching display of urlHolder for print mode and web mode
            urlHolder.style.display = urlMode;

            // switching display of footer for print mode and web mode
            document.getElementsByTagName('footer')[0].style.display = pageMode;

            // Removing Youtube embedded videos if any because they come up as black spots in the print
            embeds = document.getElementsByClassName('embed-container');
            for (i = 0; i < embeds.length; i = i + 1) {
                embeds[i].style.display = pageMode;
            }

            // Removing the redirection from different language message
            redirectMessage = document.getElementsByClassName('redirect_notification')[0];
            if (redirectMessage) {
                redirectMessage.style.display = pageMode;
            }

            // Print the document.
            if (pageMode === 'none') {
                window.print();
                // Switching back to webmode
                articleModifier();
            }

        };

        // document.readyState returns 'complete' when the dom is ready to be manipulated.
        if (document.readyState !== 'complete') {
            window.alert("Please wait for the page to load completely.");
        } else {
            // calling articleModifier causes the switch between printMode and webMode
            // First call for printMode
            articleModifier();
        }

	} else if (location.href.substring(0, 30) === "http://updates.html5rocks.com/" && location.href.length > 30) {

        var updateModifier = function () {
            'use strict';
            // I couldn't find any redirect pages for 'Update' but just in case
            // Going from redirect URL to the original English article
            if (location.href.substring(location.href.lastIndexOf('/'), location.href.lastIndexOf('/') + 22) === "/?redirect_from_locale") {
                window.alert("Redirecting you to original article. Please print the article from there.");
                window.location = window.location.href.substring(0, window.location.href.lastIndexOf('/'));
            }

            // html5rocks->update

            // switching between print and web display
            // document.getElementsByTagName('header')[0].style.display === 'block'
            // Defaults to 'false' in the first run.
            // element.style doesn't get computed styles it gets set styles
            // instead use window.getComputedStyle(element)
            // referred from here http://stackoverflow.com/questions/20329730/
            if (window.getComputedStyle(document.getElementsByTagName('header')[0]).display === 'none') {
                pageMode = 'block';
                urlMode = 'none';
            } else {
                pageMode = 'none';
                urlMode = 'block';
            }

            // Remove top header
            document.getElementsByTagName('header')[0].style.display = pageMode;

            // selecting divs so that further elements of the page can be selected
            var divs = document.getElementsByTagName('div');
            // switch margin between 4.5em to 1em to give nice spacing
            if (pageMode === 'none') {
                divs[5].style.margin = '1em auto';
            } else {
                divs[5].style.margin = '4.5em auto';
            }

            // Remove tags, blank space and google+ share
            divs[7].style.display = pageMode;
            divs[8].style.display = pageMode;
            divs[9].style.display = pageMode;

            // Setting reference div
            ref = divs[5].firstChild.nextSibling.lastChild.previousSibling;

            // switch between print mode and web mode for displaying reference
            ref.style.display = pageMode;

            // Creating URL Holder if it is not deifned
            if (typeof (urlHolder) === 'undefined') {
                // Create a new element for the URL
                urlHolder = document.createElement('section');
                // make it look like it belongs
                urlHolder.className = 'cc pattern-bg-lighter';
                // append it side by side with reference
                divs[5].appendChild(urlHolder);
                // Set innerText to the url
                urlHolder.innerText = location.href;
                // Stylising the reference
                urlHolder.style.marginLeft = '0px';
                urlHolder.style.textAlign = 'center';
                urlHolder.style.fontWeight = 'bold';
            }

            // switching display of urlHolder for print mode and web mode
            urlHolder.style.display = urlMode;

            // Print the document.
            if (pageMode === 'none') {
                window.print();
                // Switching back to webmode
                updateModifier();
            }
        };
        // document.readyState returns 'complete' when the dom is ready to be manipulated.
        if (document.readyState !== 'complete') {
            window.alert("Please wait for the page to load completely.");
        } else {
            // calling updateModifier causes the switch between printMode and webMode
            // First call for printMode
            updateModifier();
        }
	} else {
		// HTML5Rocks but not article
		window.alert("You are on html5rocks, Now Please choose an article to print");
	}
} else {
	// Some website other than HTML5Rocks
	window.alert("This extension only prettifies html5rocks Please visit http://www.html5rocks.com");
}

// size selector - a way to chose the font size
var sizeSelector = function () {
    'use strict';
    // Currently I will be rendering the choice container with the old mehtods of creating every element using javascript
    // TODO: I plan to keep HTML for the choice container in a separate file.
    // It should be have the functionality of text plugin of requirejs. https://github.com/requirejs/text
    // And rendering of Mustache. https://github.com/janl/mustache.js  --  http://coenraets.org/blog/2011/12/tutorial-html-templates-with-mustache-js/
};<commit_msg>Updated the TODO<commit_after>/****************************************************************************
 * PrettyPrintHTML5ROCKS
 * This is the script which modifies the articles on
 * http://www.html5rocks.com and make them fit for printing.
 * Author:Ishan
 * email: ishanatmuzaffarpur@gmail.com
 * Google Plus: https://plus.google.com/111814328368711145786
 ****************************************************************************/

/* Steps:
  1. Rmove the top header of the page.
  2. Remove the Table of Contents.
  3. Fill the extra space by the article content.
  4. Resize the Code Snippets
  5. Remove the number of comments.
  6. Add the URL to bottom of the article.
  7. Remove the disqus comments.
  8. Remove the footer
  9. If there are embedded videos remove them.
 10. If there is redirect message remove it.
 11. Call window.print() to print the document.
*/

/******************************************************
 *     Step By Step Code
 ******************************************************/

// jsLint global variables
/*jslint browser: true, devel: true */

// Current Working set

// Global variables
var pageMode, urlMode;
var embeds, ref, codeSnippets;
var i;
var urlHolder, redirectMessage;
// Font sizes for different modes
// 9 - small, 12 - normal, 18 - large
var articleFontSize = '12px', codeSnippetsFontSize = '10px';
var ARTICLEFONTSIZEORIGINAL = '18px', CODESNIPPETSFONTSIZEORIGINAL = '15px';

if (location.href.substring(0, 30) === "http://updates.html5rocks.com/" || location.href.substring(0, 26) === "http://www.html5rocks.com/") {
    // Breaking URL into parts
    var partsOfURL = location.href.split('/');

    if (partsOfURL[4] === "tutorials" && partsOfURL[6] !== undefined) {

        var articleModifier = function () {
            'use strict';
            // html5rocks->tutorial

            // switching between print and web display
            // document.getElementsByTagName('header')[0].style.display
            // Defaults to 'false' in the first run.
            // element.style doesn't get computed styles it gets set styles
            // instead use window.getComputedStyle(element)
            // referred from here http://stackoverflow.com/questions/20329730/
            if (window.getComputedStyle(document.getElementsByTagName('header')[0]).display === 'none') {
                pageMode = 'block';
                urlMode = 'none';
            } else {
                pageMode = 'none';
                urlMode = 'block';
            }

            // Remove top header
            document.getElementsByTagName('header')[0].style.display = pageMode;

            // selecting divs so that further elements of the page can be selected
            var divs = document.getElementsByTagName('div');

            // Hide Table of Contents
            divs[1].style.display = pageMode;

            // switching the article between print mode and web mode
            if (pageMode === 'none') {
                // Making article fill the screen
                divs[2].style.marginLeft = '0px';
                divs[2].style.maxWidth = 'inherit';
                divs[2].style.width = '100%';
                // Making text small
                divs[2].style.fontSize = articleFontSize;
                // Reduce the line-height
                divs[2].style.lineHeight = 1.0;
            } else {
                // Making article shrink back
                divs[2].style.marginLeft = '350px';
                divs[2].style.maxWidth = '660px';
                divs[2].style.width = '87%';
                //Enlarging the text again
                divs[2].style.fontSize = ARTICLEFONTSIZEORIGINAL;
                // Reset the line-height
                divs[2].style.lineHeight = 1.5;
            }

            // Resizng the code snippets
            codeSnippets = document.getElementsByClassName('prettyprint');
            if (pageMode === 'none') {
                for (i = codeSnippets.length - 1; i >= 0; i = i - 1) {
                    codeSnippets[i].style.fontSize = codeSnippetsFontSize;
                }
            } else {
                for (i = codeSnippets.length - 1; i >= 0; i = i - 1) {
                    codeSnippets[i].style.fontSize = CODESNIPPETSFONTSIZEORIGINAL;
                }
            }

            // Remove the number of comments
            document.getElementsByClassName('load-comments')[0].parentElement.style.display = pageMode;

            // Creating URL Holder if it is not deifned
            if (typeof (urlHolder) === 'undefined') {
                // Create a new element for the URL
                urlHolder = document.createElement('section');
                // make it look like it belongs
                urlHolder.className = 'cc pattern-bg-lighter';
                // append it after the article
                divs[2].appendChild(urlHolder);

                // Set innerText to the url
                urlHolder.innerText = location.href;
                // Stylising the reference
                urlHolder.style.marginLeft = '0px';
                urlHolder.style.textAlign = 'center';
                urlHolder.style.fontWeight = 'bold';
                urlHolder.style.paddingTop = '20px';
            }

            // switching display of disqus comments for print mode and web mode
            document.getElementById('disqus').style.display = pageMode;

            // switching display of urlHolder for print mode and web mode
            urlHolder.style.display = urlMode;

            // switching display of footer for print mode and web mode
            document.getElementsByTagName('footer')[0].style.display = pageMode;

            // Removing Youtube embedded videos if any because they come up as black spots in the print
            embeds = document.getElementsByClassName('embed-container');
            for (i = 0; i < embeds.length; i = i + 1) {
                embeds[i].style.display = pageMode;
            }

            // Removing the redirection from different language message
            redirectMessage = document.getElementsByClassName('redirect_notification')[0];
            if (redirectMessage) {
                redirectMessage.style.display = pageMode;
            }

            // Print the document.
            if (pageMode === 'none') {
                window.print();
                // Switching back to webmode
                articleModifier();
            }

        };

        // document.readyState returns 'complete' when the dom is ready to be manipulated.
        if (document.readyState !== 'complete') {
            window.alert("Please wait for the page to load completely.");
        } else {
            // calling articleModifier causes the switch between printMode and webMode
            // First call for printMode
            articleModifier();
        }

	} else if (location.href.substring(0, 30) === "http://updates.html5rocks.com/" && location.href.length > 30) {

        var updateModifier = function () {
            'use strict';
            // I couldn't find any redirect pages for 'Update' but just in case
            // Going from redirect URL to the original English article
            if (location.href.substring(location.href.lastIndexOf('/'), location.href.lastIndexOf('/') + 22) === "/?redirect_from_locale") {
                window.alert("Redirecting you to original article. Please print the article from there.");
                window.location = window.location.href.substring(0, window.location.href.lastIndexOf('/'));
            }

            // html5rocks->update

            // switching between print and web display
            // document.getElementsByTagName('header')[0].style.display === 'block'
            // Defaults to 'false' in the first run.
            // element.style doesn't get computed styles it gets set styles
            // instead use window.getComputedStyle(element)
            // referred from here http://stackoverflow.com/questions/20329730/
            if (window.getComputedStyle(document.getElementsByTagName('header')[0]).display === 'none') {
                pageMode = 'block';
                urlMode = 'none';
            } else {
                pageMode = 'none';
                urlMode = 'block';
            }

            // Remove top header
            document.getElementsByTagName('header')[0].style.display = pageMode;

            // selecting divs so that further elements of the page can be selected
            var divs = document.getElementsByTagName('div');
            // switch margin between 4.5em to 1em to give nice spacing
            if (pageMode === 'none') {
                divs[5].style.margin = '1em auto';
            } else {
                divs[5].style.margin = '4.5em auto';
            }

            // Remove tags, blank space and google+ share
            divs[7].style.display = pageMode;
            divs[8].style.display = pageMode;
            divs[9].style.display = pageMode;

            // Setting reference div
            ref = divs[5].firstChild.nextSibling.lastChild.previousSibling;

            // switch between print mode and web mode for displaying reference
            ref.style.display = pageMode;

            // Creating URL Holder if it is not deifned
            if (typeof (urlHolder) === 'undefined') {
                // Create a new element for the URL
                urlHolder = document.createElement('section');
                // make it look like it belongs
                urlHolder.className = 'cc pattern-bg-lighter';
                // append it side by side with reference
                divs[5].appendChild(urlHolder);
                // Set innerText to the url
                urlHolder.innerText = location.href;
                // Stylising the reference
                urlHolder.style.marginLeft = '0px';
                urlHolder.style.textAlign = 'center';
                urlHolder.style.fontWeight = 'bold';
            }

            // switching display of urlHolder for print mode and web mode
            urlHolder.style.display = urlMode;

            // Print the document.
            if (pageMode === 'none') {
                window.print();
                // Switching back to webmode
                updateModifier();
            }
        };
        // document.readyState returns 'complete' when the dom is ready to be manipulated.
        if (document.readyState !== 'complete') {
            window.alert("Please wait for the page to load completely.");
        } else {
            // calling updateModifier causes the switch between printMode and webMode
            // First call for printMode
            updateModifier();
        }
	} else {
		// HTML5Rocks but not article
		window.alert("You are on html5rocks, Now Please choose an article to print");
	}
} else {
	// Some website other than HTML5Rocks
	window.alert("This extension only prettifies html5rocks Please visit http://www.html5rocks.com");
}

// size selector - a way to chose the font size
var sizeSelector = function () {
    'use strict';
    // Currently I will be rendering the choice container with the old mehtods of creating every element using javascript
    // TODO: I plan to keep HTML for the choice container in a separate file.
    // It should be having the functionality of text plugin of requirejs. https://github.com/requirejs/text
    // And rendering of Mustache. https://github.com/janl/mustache.js  --  http://coenraets.org/blog/2011/12/tutorial-html-templates-with-mustache-js/
    // I am hoping to handle the text plugin and mustache using git submodules.

};<|endoftext|>


<commit_before>var ERR = require('async-stacktrace');
var _ = require('lodash');
var path = require('path');
var csvStringify = require('csv').stringify;
var express = require('express');
var router = express.Router();

var error = require('../../lib/error');
var logger = require('../../lib/logger');
var filePaths = require('../../lib/file-paths');
var questionServers = require('../../question-servers');
var sqldb = require('../../lib/sqldb');
var sqlLoader = require('../../lib/sql-loader');

var sql = sqlLoader.loadSqlEquiv(__filename);

var handle = function(req, res, next) {
    if (req.body.postAction) {
        if (req.body.postAction == 'submitQuestionAnswer') {
            if (!req.body.postData) return callback(error.make(400, 'No postData', {locals: res.locals, body: req.body}));
            var postData;
            try {
                postData = JSON.parse(req.body.postData);
            } catch (e) {
                return callback(error.make(400, 'JSON parse failed on body.postData', {locals: res.locals, body: req.body}));
            }

            var variant = postData.variant;
            submission = {
                submitted_answer: postData.submittedAnswer,
            };
            questionServers.gradeSubmission(submission, variant, res.locals.question, res.locals.course, {}, function(err, grading) {
                if (ERR(err, next)) return;
                _.assign(submission, grading);
                // hack to make partials/submissionStatus.js do the right thing
                submission.graded_at = 'Graded';
                // localscripts/question.js expects there to be an array of submission objects
                res.locals.submissions = [submission];
                questionServers.getModule(res.locals.question.type, function(err, questionModule) {
                    if (ERR(err, next)) return;
                    questionModule.renderSubmission(variant, res.locals.question, submission, res.locals.course, res.locals, function(err, submissionHtml) {
                        if (ERR(err, next)) return;
                        questionModule.renderTrueAnswer(variant, res.locals.question, res.locals.course, res.locals, function(err, answerHtml) {
                            if (ERR(err, next)) return;
                            render(req, res, next, variant, submission, submissionHtml, answerHtml);
                        });
                    });
                });
            });
        } else return next(error.make(400, 'unknown postAction', {locals: res.locals, body: req.body}));
    } else {
        questionServers.makeVariant(res.locals.question, res.locals.course, {}, function(err, variant) {
            if (ERR(err, next)) return;
            render(req, res, next, variant);
        });
    }
};

var render = function(req, res, next, variant, submission, submissionHtml, answerHtml) {
    var params = [res.locals.question.id, res.locals.course_instance.id];
    sqldb.queryOneRow(sql.select_question, params, function(err, result) {
        if (ERR(err, next)) return;
        questionServers.getEffectiveQuestionType(res.locals.question.type, function(err, effectiveQuestionType) {
            if (ERR(err, next)) return;
            questionServers.getModule(res.locals.question.type, function(err, questionModule) {
                if (ERR(err, next)) return;
                questionModule.renderExtraHeaders(res.locals.question, res.locals.course, res.locals, function(err, extraHeaders) {
                    if (ERR(err, next)) return;
                    questionModule.renderQuestion(variant, res.locals.question, null, res.locals.course, res.locals, function(err, questionHtml) {
                        if (ERR(err, next)) return;

                        res.locals.result = result.rows[0];
                        res.locals.effectiveQuestionType = effectiveQuestionType,
                        res.locals.submission = submission;
                        res.locals.extraHeaders = extraHeaders;
                        res.locals.questionHtml = questionHtml;
                        res.locals.submissionHtml = submissionHtml;
                        res.locals.answerHtml = answerHtml;
                        res.locals.postUrl = res.locals.urlPrefix + "/instructor/question/" + res.locals.question.id + "/";
                        res.locals.questionJson = JSON.stringify({
                            questionFilePath: res.locals.urlPrefix + "/instructor/question/" + res.locals.question.id + "/file",
                            question: res.locals.question,
                            effectiveQuestionType: effectiveQuestionType,
                            course: res.locals.course,
                            courseInstance: res.locals.course_instance,
                            variant: variant,
                            submittedAnswer: submission ? submission.submitted_answer : null,
                            feedback: submission ? submission.feedback : null,
                            trueAnswer: variant.true_answer,
                            submissions: submission ? res.locals.submissions : null,
                        });
                        res.render(__filename.replace(/\.js$/, '.ejs'), res.locals);
                    });
                });
            });
        });
    });
};

router.get('/', handle);
router.post('/', handle);

router.get('/file/:filename', function(req, res, next) {
    var question = res.locals.question;
    var course = res.locals.course;
    var filename = req.params.filename;
    filePaths.questionFilePath(filename, question.directory, course.path, question, function(err, fullPath, effectiveFilename, rootPath) {
        if (ERR(err, next)) return;
        res.sendFile(effectiveFilename, {root: rootPath});
    });
});

router.get('/text/:filename', function(req, res, next) {
    var question = res.locals.question;
    var course = res.locals.course;
    var filename = 'text/' + req.params.filename;
    filePaths.questionFilePath(filename, question.directory, course.path, question, function(err, fullPath, effectiveFilename, rootPath) {
        if (ERR(err, next)) return;
        res.sendFile(effectiveFilename, {root: rootPath});
    });
});

module.exports = router;
<commit_msg>don't pass trueAnswer to instructorQuestion before submission; close #451<commit_after>var ERR = require('async-stacktrace');
var _ = require('lodash');
var path = require('path');
var csvStringify = require('csv').stringify;
var express = require('express');
var router = express.Router();

var error = require('../../lib/error');
var logger = require('../../lib/logger');
var filePaths = require('../../lib/file-paths');
var questionServers = require('../../question-servers');
var sqldb = require('../../lib/sqldb');
var sqlLoader = require('../../lib/sql-loader');

var sql = sqlLoader.loadSqlEquiv(__filename);

var handle = function(req, res, next) {
    if (req.body.postAction) {
        if (req.body.postAction == 'submitQuestionAnswer') {
            if (!req.body.postData) return callback(error.make(400, 'No postData', {locals: res.locals, body: req.body}));
            var postData;
            try {
                postData = JSON.parse(req.body.postData);
            } catch (e) {
                return callback(error.make(400, 'JSON parse failed on body.postData', {locals: res.locals, body: req.body}));
            }

            var variant = postData.variant;
            submission = {
                submitted_answer: postData.submittedAnswer,
            };
            questionServers.gradeSubmission(submission, variant, res.locals.question, res.locals.course, {}, function(err, grading) {
                if (ERR(err, next)) return;
                _.assign(submission, grading);
                // hack to make partials/submissionStatus.js do the right thing
                submission.graded_at = 'Graded';
                // localscripts/question.js expects there to be an array of submission objects
                res.locals.submissions = [submission];
                questionServers.getModule(res.locals.question.type, function(err, questionModule) {
                    if (ERR(err, next)) return;
                    questionModule.renderSubmission(variant, res.locals.question, submission, res.locals.course, res.locals, function(err, submissionHtml) {
                        if (ERR(err, next)) return;
                        questionModule.renderTrueAnswer(variant, res.locals.question, res.locals.course, res.locals, function(err, answerHtml) {
                            if (ERR(err, next)) return;
                            render(req, res, next, variant, submission, submissionHtml, answerHtml);
                        });
                    });
                });
            });
        } else return next(error.make(400, 'unknown postAction', {locals: res.locals, body: req.body}));
    } else {
        questionServers.makeVariant(res.locals.question, res.locals.course, {}, function(err, variant) {
            if (ERR(err, next)) return;
            render(req, res, next, variant);
        });
    }
};

var render = function(req, res, next, variant, submission, submissionHtml, answerHtml) {
    var params = [res.locals.question.id, res.locals.course_instance.id];
    sqldb.queryOneRow(sql.select_question, params, function(err, result) {
        if (ERR(err, next)) return;
        questionServers.getEffectiveQuestionType(res.locals.question.type, function(err, effectiveQuestionType) {
            if (ERR(err, next)) return;
            questionServers.getModule(res.locals.question.type, function(err, questionModule) {
                if (ERR(err, next)) return;
                questionModule.renderExtraHeaders(res.locals.question, res.locals.course, res.locals, function(err, extraHeaders) {
                    if (ERR(err, next)) return;
                    questionModule.renderQuestion(variant, res.locals.question, null, res.locals.course, res.locals, function(err, questionHtml) {
                        if (ERR(err, next)) return;

                        res.locals.result = result.rows[0];
                        res.locals.effectiveQuestionType = effectiveQuestionType,
                        res.locals.submission = submission;
                        res.locals.extraHeaders = extraHeaders;
                        res.locals.questionHtml = questionHtml;
                        res.locals.submissionHtml = submissionHtml;
                        res.locals.answerHtml = answerHtml;
                        res.locals.postUrl = res.locals.urlPrefix + "/instructor/question/" + res.locals.question.id + "/";
                        res.locals.questionJson = JSON.stringify({
                            questionFilePath: res.locals.urlPrefix + "/instructor/question/" + res.locals.question.id + "/file",
                            question: res.locals.question,
                            effectiveQuestionType: effectiveQuestionType,
                            course: res.locals.course,
                            courseInstance: res.locals.course_instance,
                            variant: variant,
                            submittedAnswer: submission ? submission.submitted_answer : null,
                            feedback: submission ? submission.feedback : null,
                            trueAnswer: submission ? variant.true_answer : null,
                            submissions: submission ? res.locals.submissions : null,
                        });
                        res.render(__filename.replace(/\.js$/, '.ejs'), res.locals);
                    });
                });
            });
        });
    });
};

router.get('/', handle);
router.post('/', handle);

router.get('/file/:filename', function(req, res, next) {
    var question = res.locals.question;
    var course = res.locals.course;
    var filename = req.params.filename;
    filePaths.questionFilePath(filename, question.directory, course.path, question, function(err, fullPath, effectiveFilename, rootPath) {
        if (ERR(err, next)) return;
        res.sendFile(effectiveFilename, {root: rootPath});
    });
});

router.get('/text/:filename', function(req, res, next) {
    var question = res.locals.question;
    var course = res.locals.course;
    var filename = 'text/' + req.params.filename;
    filePaths.questionFilePath(filename, question.directory, course.path, question, function(err, fullPath, effectiveFilename, rootPath) {
        if (ERR(err, next)) return;
        res.sendFile(effectiveFilename, {root: rootPath});
    });
});

module.exports = router;
<|endoftext|>


<commit_before>/*************************
 * TRAVIS DEV BUILD STEPS
 *************************/
const { exec, execSync, spawn } = require('child_process');
const util               = require('util');
const execPromise        = util.promisify(exec);

/* Steps
 ********/
const Steps = (paths, components) => { // :{}
	return {
		cloneComponentRepos() { // :Promise[{}] - (runs asynchronously)
			// const cloneCmd = 'git clone --depth 1';
			const opts     = { cwd: paths.components };
			let promises   = [];

			for (const [i, repoName] of components.repoNames.entries()) {
				console.info(`cloning ${components.names[i]}`.toUpperCase().alert);
				// const cmd = `${cloneCmd} ${repoName}`;

				const promise = new Promise((resolve, reject) => {
					const git = spawn('git', ['clone', '--progress', '--depth', '1', repoName], opts);

					git.stdout.on('data', data => {
						console.log(`STDOUT: ${data}`);
					});

					git.stderr.on('data', data => {
						console.log(`STDERR: ${data}`);
					});

					git.on('close', code => {
						console.log(`child process exited with code ${code}`);
						resolve(true);
					});

					git.on('error', err => {
						console.log('Failed to start subprocess.');
						reject(err);
					});
				})
				// const promise = execPromise(cmd, opts).then(result => {
				// 	console.log('RESULT:', result);
				// 	return result;
				// }).catch(error => {
				// 	console.error('error: clone component repos'.toUpperCase().error);
				// 	console.error(error);
				// 	process.exit(1);
				// });

				promises.push(promise);
			}

			return Promise.all(promises);
		},

		// cloneComponentRepos() { // :Promise[{}] - (runs asynchronously)
		// 	const cloneCmd = 'git clone --depth 1';
		// 	const opts     = { cwd: paths.components };
		// 	let promises   = [];
		// 	for (const [i, repoName] of components.repoNames.entries()) {
		// 		console.info(`cloning ${components.names[i]}`.toUpperCase().alert);
		// 		const cmd     = `${cloneCmd} ${repoName}`;
		// 		const promise = execPromise(cmd, opts).then(result => {
		// 			console.log('RESULT:', result);
		// 			return result;
		// 		}).catch(error => {
		// 			console.error('error: clone component repos'.toUpperCase().error);
		// 			console.error(error);
		// 			process.exit(1);
		// 		});
		// 		promises.push(promise);
		// 	}
		// 	return Promise.all(promises);
		// },

		setupComponents() { // :Promise[{}] - (runs asynchronously)
			const cmd    = 'rapid-build prod publish && npm run link'
			let promises = [];
			for (const name of components.names) {
				console.info(`setup component ${name}`.toUpperCase().alert);
				const opts    = { cwd: `${paths.components}/${name}` };
				const promise = execPromise(cmd, opts).then(result => {
					console.log('RESULT:', result);
					return result;
				}).catch(error => {
					console.error('error: setup components'.toUpperCase().error);
					console.error(error);
					process.exit(1);
				});
				promises.push(promise);
			}
			return Promise.all(promises);
		},

		setupShowcase() { // :void - (runs synchronously)
			const cmd  = 'npm run setup'
			const opts = { cwd: paths.showcase, stdio: [0,1,2] };
			console.info(`setup showcase`.toUpperCase().alert);
			execSync(cmd, opts); console.log();
		},

		buildShowcase() { // :void - (runs synchronously)
			const cmd  = 'rapid-build prod publish'
			const opts = { cwd: paths.showcase, stdio: [0,1,2] };
			console.info(`build showcase`.toUpperCase().alert);
			execSync(cmd, opts); console.log();
		}
	};
};

/* Export It!
 *************/
module.exports = Steps;
<commit_msg>chore(travis): try to clone components asynchronously with node spawn<commit_after>/*************************
 * TRAVIS DEV BUILD STEPS
 *************************/
const { exec, execSync, spawn } = require('child_process');
const util               = require('util');
const execPromise        = util.promisify(exec);

/* Steps
 ********/
const Steps = (paths, components) => { // :{}
	return {
		// cloneComponentRepos() { // :Promise[{}] - (runs asynchronously)
		// 	const opts     = { cwd: paths.components };
		// 	let promises   = [];
		//
		// 	for (const [i, repoName] of components.repoNames.entries()) {
		// 		console.info(`cloning ${components.names[i]}`.toUpperCase().alert);
		//
		// 		const promise = new Promise((resolve, reject) => {
		// 			const git = spawn('git', ['clone', '--progress', '--depth', '1', repoName], opts);
		//
		// 			git.stdout.on('data', data => {
		// 				console.log(`STDOUT: ${data}`);
		// 			});
		//
		// 			git.stderr.on('data', data => {
		// 				console.log(`STDERR: ${data}`);
		// 			});
		//
		// 			git.on('close', code => {
		// 				console.log(`child process exited with code ${code}`);
		// 				resolve(true);
		// 			});
		//
		// 			git.on('error', err => {
		// 				console.log('Failed to start subprocess.');
		// 				reject(err);
		// 			});
		// 		})
		//
		// 		promises.push(promise);
		// 	}
		//
		// 	return Promise.all(promises);
		// },

		cloneComponentRepos() { // :Promise[{}] - (runs asynchronously)
			const cloneCmd = 'git clone --progress --depth 1';
			const opts     = { cwd: paths.components };
			let promises   = [];
			for (const [i, repoName] of components.repoNames.entries()) {
				console.info(`cloning ${components.names[i]}`.toUpperCase().alert);
				const cmd     = `${cloneCmd} ${repoName}`;
				const promise = execPromise(cmd, opts).then(result => {
					console.log('RESULT:', result);
					return result;
				}).catch(error => {
					console.error('error: clone component repos'.toUpperCase().error);
					console.error(error);
					process.exit(1);
				});
				promises.push(promise);
			}
			return Promise.all(promises);
		},

		setupComponents() { // :Promise[{}] - (runs asynchronously)
			const cmd    = 'rapid-build prod publish && npm run link'
			let promises = [];
			for (const name of components.names) {
				console.info(`setup component ${name}`.toUpperCase().alert);
				const opts    = { cwd: `${paths.components}/${name}` };
				const promise = execPromise(cmd, opts).then(result => {
					console.log('RESULT:', result);
					return result;
				}).catch(error => {
					console.error('error: setup components'.toUpperCase().error);
					console.error(error);
					process.exit(1);
				});
				promises.push(promise);
			}
			return Promise.all(promises);
		},

		setupShowcase() { // :void - (runs synchronously)
			const cmd  = 'npm run setup'
			const opts = { cwd: paths.showcase, stdio: [0,1,2] };
			console.info(`setup showcase`.toUpperCase().alert);
			execSync(cmd, opts); console.log();
		},

		buildShowcase() { // :void - (runs synchronously)
			const cmd  = 'rapid-build prod publish'
			const opts = { cwd: paths.showcase, stdio: [0,1,2] };
			console.info(`build showcase`.toUpperCase().alert);
			execSync(cmd, opts); console.log();
		}
	};
};

/* Export It!
 *************/
module.exports = Steps;
<|endoftext|>


<commit_before>/**
 * @class AbstractBaseDao
 * @classdesc A NoSQL basic implementation optimized for redis.  It also serves as a facade
 * for other NoSQL databases like leveldb, couch, etc.
 *
 * @author: darryl.west@raincitysoftware.com
 * @created: 9/2/14
 */
const dash = require('lodash'),
    uuid = require('node-uuid');

const AbstractBaseDao = function(options) {
    'use strict';

    const dao = this,
        log = options.log,
        domain = options.domain,
        createType = options.createType;

    /**
     * create a unique model id
     * @returns a guid-like thing
     */
    this.createModelId = function() {
        return uuid.v4().replace(/-/g, '');
    };

    /**
     * create a domain key by combining domain, colon and the id
     *
     * @param id - the model id; if id is null an error is thrown
     * @returns domain key
     */
    this.createDomainKey = function(id) {
        if (!id) {
            throw new Error('domain key requires model id');
        }

        if (id.indexOf( domain ) === 0) {
            return id;
        } else {
            return [ domain, ':', id ].join('');
        }
    };

    /**
     * query the domain for rows.  this is a very simple implementation that pulls
     * all rows for the given domain.  for production you probably want to override
     * this with a fully implemented query method.  but if your row count is less than
     * a few hundred, then this should work.
     *
     * @param client - a nosql client, e.g. redis
     * @param request - the query request object
     * @param callback err, response
     */
    this.query = function(client, request, callback) {
        if (!callback && typeof request === 'function') {
            callback = request;
        }

        const keysCallback = function(err, keys) {
            let list = [];

            if (err) {
                log.error( err );
                callback( err );
            }

            const loopCallback = function(err, model) {
                if (err) {
                    log.error( err );
                } else if (model) {
                    list.push( model );
                }

                let key = keys.shift();

                if (key) {
                    dao.findById( client, key, loopCallback );
                } else {
                    return callback( err, list );
                }
            };

            loopCallback();
        };

        // pull all the keys
        client.keys( dao.createDomainKey( '*' ), keysCallback );
    };

    /**
     * query a standard index set, fetch, parse and return the models
     *
     * @param client - redis client
     * @param idx - the index name (key)
     * @param completeCallback - err, list
     */
    this.queryByIndexSet = function(client, idx, completeCallback) {
        const callback = function(err, list) {
            if (err) {
                return completeCallback(err);
            }

            if (list && list.length > 0) {
                return completeCallback( null, dao.parseModelList( list ));
            } else {
                return completeCallback( null, [] );
            }
        };

        client.smembers(idx, function(err, keys) {
            if (err) {
                return completeCallback(err);
            }

            if (keys && keys.length > 0) {
                log.info(`found ${keys.length} keys for ${idx}`);
                client.mget(keys, callback);
            } else {
                log.info('zero keys for index: ', idx);
                return completeCallback( null, [] );
            }
        });
    };

    /**
     * find the domain row for the given id.
     *
     * @param client - a nosql client, e.g. redis
     * @param id - the id of the object
     * @param callback err, response
     */
    this.findById = function(client, id, callback) {
        const key = dao.createDomainKey( id );

        const foundCallback = function(err, result) {
            let model;

            if (result) {
                model = dao.parseModel( result );
            }

            callback( err, model );
        };

        log.debug('find the model with key: ', key);
        client.get( key, foundCallback );
    };

    /**
     * prepare the domain model for update or insert.
     *  - create an id if necessary;
     *  - create a dateCreated if necessary
     *  - set the lastUpdated to now
     *  - set the version to zero if no version exists (does not increment the version)
     *
     * @param model - the domain data model object
     * @return - a copy of the model
     */
    this.prepareUpdate = function(model) {
        // get a copy...
        model = dash.clone( model );

        if (!model.id) {
            model.id = dao.createModelId();
        }

        if (!model.dateCreated) {
            model.dateCreated = new Date();
        }

        model.lastUpdated = new Date();

        if (!dash.isNumber( model.version )) {
            model.version = 0;
        }

        return model;
    };

    /**
     * insert the domain model.
     *
     * @param client - a nosql client, e.g. redis
     * @param model - the domain data model object
     * @param callback err, response
     */
    this.insert = function(client, model, callback) {
        model = dao.prepareUpdate( model );
        let key = dao.createDomainKey( model.id );
        let json = JSON.stringify( model );

        const insertCallback = function(err, status) {
            callback( err, model );
        };

        log.debug('insert model: ', model);
        client.set(key, json, insertCallback);
    };

    /**
     * update the domain model.
     *
     * @param client - a nosql client, e.g. redis
     * @param model - the domain data model object
     * @param callback err, response
     */
    this.update = function(client, model, callback) {
        model = dao.prepareUpdate( model );
        model.version = model.version + 1;
        let key = dao.createDomainKey( model.id );
        let json = JSON.stringify( model );

        const updateCallback = function(err, status) {
            callback( err, model );
        };

        log.debug('update model: ', model);
        client.set(key, json, updateCallback);
    };

    /**
     * @param list - a list of models
     */
    this.parseModelList = function(list) {
        return list.map(obj => {
            return dao.parseModel( obj );
        });
    };

    /**
     * parse the model (if JSON string) and set dateCreated and lastUpdated to date types
     *
     * @param value JSON string or model object
     * @returns model
     */
    this.parseModel = function(value) {
        let model;

        if (typeof value === 'string') {
            model = JSON.parse( value );
        } else {
            model = value;
        }

        if (typeof model.dateCreated === 'string') {
            model.dateCreated = new Date( model.dateCreated );
        }

        if (typeof model.lastUpdated === 'string') {
            model.lastUpdated = new Date( model.lastUpdated );
        }

        if (typeof createType === 'function') {
            return createType( model );
        } else {
            return model;
        }
    };

    // constructor validations
    if (!log) {
        throw new Error('dao must be constructed with a log');
    }
    if (!domain) {
        throw new Error('dao must be constructed with a domain');
    }
};

/**
 * extend the public methods of this abstract class to a child class.
 *
 * @param child - the extending class/object
 * @param options - must include a log and domain
 * @returns parent reference
 */
AbstractBaseDao.extend = function(child, options) {
    'use strict';

    const parent = new AbstractBaseDao( options );

    dash.extend( child, parent );

    return parent;
};

module.exports = AbstractBaseDao;
<commit_msg>added note to replace keys with scan in query<commit_after>/**
 * @class AbstractBaseDao
 * @classdesc A NoSQL basic implementation optimized for redis.  It also serves as a facade
 * for other NoSQL databases like leveldb, couch, etc.
 *
 * @author: darryl.west@raincitysoftware.com
 * @created: 9/2/14
 */
const dash = require('lodash'),
    uuid = require('node-uuid');

const AbstractBaseDao = function(options) {
    'use strict';

    const dao = this,
        log = options.log,
        domain = options.domain,
        createType = options.createType;

    /**
     * create a unique model id
     * @returns a guid-like thing
     */
    this.createModelId = function() {
        return uuid.v4().replace(/-/g, '');
    };

    /**
     * create a domain key by combining domain, colon and the id
     *
     * @param id - the model id; if id is null an error is thrown
     * @returns domain key
     */
    this.createDomainKey = function(id) {
        if (!id) {
            throw new Error('domain key requires model id');
        }

        if (id.indexOf( domain ) === 0) {
            return id;
        } else {
            return [ domain, ':', id ].join('');
        }
    };

    /**
     * query the domain for rows.  this is a very simple implementation that pulls
     * all rows for the given domain.  for production you probably want to override
     * this with a fully implemented query method.  but if your row count is less than
     * a few hundred, then this should work.
     *
     * @param client - a nosql client, e.g. redis
     * @param request - the query request object
     * @param callback err, response
     */
    this.query = function(client, request, callback) {
        if (!callback && typeof request === 'function') {
            callback = request;
        }

        const keysCallback = function(err, keys) {
            let list = [];

            if (err) {
                log.error( err );
                callback( err );
            }

            const loopCallback = function(err, model) {
                if (err) {
                    log.error( err );
                } else if (model) {
                    list.push( model );
                }

                let key = keys.shift();

                if (key) {
                    dao.findById( client, key, loopCallback );
                } else {
                    return callback( err, list );
                }
            };

            loopCallback();
        };

        // TODO : replace with scan
        client.keys( dao.createDomainKey( '*' ), keysCallback );
    };

    /**
     * query a standard index set, fetch, parse and return the models
     *
     * @param client - redis client
     * @param idx - the index name (key)
     * @param completeCallback - err, list
     */
    this.queryByIndexSet = function(client, idx, completeCallback) {
        const callback = function(err, list) {
            if (err) {
                return completeCallback(err);
            }

            if (list && list.length > 0) {
                return completeCallback( null, dao.parseModelList( list ));
            } else {
                return completeCallback( null, [] );
            }
        };

        client.smembers(idx, function(err, keys) {
            if (err) {
                return completeCallback(err);
            }

            if (keys && keys.length > 0) {
                log.info(`found ${keys.length} keys for ${idx}`);
                client.mget(keys, callback);
            } else {
                log.info('zero keys for index: ', idx);
                return completeCallback( null, [] );
            }
        });
    };

    /**
     * find the domain row for the given id.
     *
     * @param client - a nosql client, e.g. redis
     * @param id - the id of the object
     * @param callback err, response
     */
    this.findById = function(client, id, callback) {
        const key = dao.createDomainKey( id );

        const foundCallback = function(err, result) {
            let model;

            if (result) {
                model = dao.parseModel( result );
            }

            callback( err, model );
        };

        log.debug('find the model with key: ', key);
        client.get( key, foundCallback );
    };

    /**
     * prepare the domain model for update or insert.
     *  - create an id if necessary;
     *  - create a dateCreated if necessary
     *  - set the lastUpdated to now
     *  - set the version to zero if no version exists (does not increment the version)
     *
     * @param model - the domain data model object
     * @return - a copy of the model
     */
    this.prepareUpdate = function(model) {
        // get a copy...
        model = dash.clone( model );

        if (!model.id) {
            model.id = dao.createModelId();
        }

        if (!model.dateCreated) {
            model.dateCreated = new Date();
        }

        model.lastUpdated = new Date();

        if (!dash.isNumber( model.version )) {
            model.version = 0;
        }

        return model;
    };

    /**
     * insert the domain model.
     *
     * @param client - a nosql client, e.g. redis
     * @param model - the domain data model object
     * @param callback err, response
     */
    this.insert = function(client, model, callback) {
        model = dao.prepareUpdate( model );
        let key = dao.createDomainKey( model.id );
        let json = JSON.stringify( model );

        const insertCallback = function(err, status) {
            callback( err, model );
        };

        log.debug('insert model: ', model);
        client.set(key, json, insertCallback);
    };

    /**
     * update the domain model.
     *
     * @param client - a nosql client, e.g. redis
     * @param model - the domain data model object
     * @param callback err, response
     */
    this.update = function(client, model, callback) {
        model = dao.prepareUpdate( model );
        model.version = model.version + 1;
        let key = dao.createDomainKey( model.id );
        let json = JSON.stringify( model );

        const updateCallback = function(err, status) {
            callback( err, model );
        };

        log.debug('update model: ', model);
        client.set(key, json, updateCallback);
    };

    /**
     * @param list - a list of models
     */
    this.parseModelList = function(list) {
        return list.map(obj => {
            return dao.parseModel( obj );
        });
    };

    /**
     * parse the model (if JSON string) and set dateCreated and lastUpdated to date types
     *
     * @param value JSON string or model object
     * @returns model
     */
    this.parseModel = function(value) {
        let model;

        if (typeof value === 'string') {
            model = JSON.parse( value );
        } else {
            model = value;
        }

        if (typeof model.dateCreated === 'string') {
            model.dateCreated = new Date( model.dateCreated );
        }

        if (typeof model.lastUpdated === 'string') {
            model.lastUpdated = new Date( model.lastUpdated );
        }

        if (typeof createType === 'function') {
            return createType( model );
        } else {
            return model;
        }
    };

    // constructor validations
    if (!log) {
        throw new Error('dao must be constructed with a log');
    }
    if (!domain) {
        throw new Error('dao must be constructed with a domain');
    }
};

/**
 * extend the public methods of this abstract class to a child class.
 *
 * @param child - the extending class/object
 * @param options - must include a log and domain
 * @returns parent reference
 */
AbstractBaseDao.extend = function(child, options) {
    'use strict';

    const parent = new AbstractBaseDao( options );

    dash.extend( child, parent );

    return parent;
};

module.exports = AbstractBaseDao;
<|endoftext|>


<commit_before>// ==UserScript==
// @name        GitHub: inline patch view
// @description Clicking on a commit ID shows the patch inline.  Second click opens the link.
// @license     2-clause BSDL
// @author      Akinori MUSHA
// @include     https://github.com/*/*/commits
// @include     https://github.com/*/*/commits/*
// @include     https://github.com/*/*/pull/*
// @version     1.0.0
// @homepage    https://github.com/knu/userjs-github_inline_patch_view
// @grant       none
// ==/UserScript==
"use strict";
(function () {
    let cloneNode = function (node) {
        let clone = document.createElement(node.tagName);
        Array.prototype.forEach.
            call(node.attributes,
                 function (attr) {
                     clone.setAttribute(attr.name, attr.value);
                 });
        return clone;
    };
    let insertInlinePatch = function (commit, sha) {
        if (commit.classList.contains("inline-patch")) {
            return false;
        }
        let url = sha.href;
        let xhr = new XMLHttpRequest();
        xhr.onload = function () {
            let patch = this.responseXML.getElementById("files");
            switch (commit.tagName) {
            case "TR":
                // Split the table to avoid CSS rule conflicts
                let container = null;
                for (let node = commit.parentNode;
                     node !== null;
                     node = node.parentNode) {
                    let clone = cloneNode(node);
                    if (container === null) {
                        // Move following siblings to a new container
                        let siblings = [];
                        for (let sibling = commit.nextSibling;
                             sibling !== null;
                             sibling = sibling.nextSibling) {
                            siblings.push(sibling);
                        }
                        siblings.forEach(function (sibling) {
                            clone.appendChild(sibling);
                        });
                    } else {
                        clone.appendChild(container);
                    }
                    container = clone;
                    if (node.tagName === "TABLE") {
                        node.parentNode.insertBefore(container, node.nextSibling);
                        patch.style.marginLeft = commit.querySelector(".commit-message").offsetLeft.toString() + "px";
                        node.parentNode.insertBefore(patch, container);
                        break;
                    }
                }
                break;
            default:
                let meta = commit.querySelector(".commit-meta");
                if (meta) {
                    meta.parentNode.appendChild(patch);
                }
            }
            commit.classList.add("inline-patch");
        };
        xhr.onerror = function () {
            console.log("Failed to load the patch from " + url);
        };
        xhr.open("GET", url);
        xhr.responseType = "document";
        xhr.send();
        return true;
    };
    let activateInlinePatch = function (commit) {
        let sha = commit.querySelector("a.sha[href*='/commit/'], a.commit-id[href*='/commit/']");
        if (!sha) {
            return;
        }
        sha.addEventListener("click",
                             function (e) {
                                 if (insertInlinePatch(commit, sha)) {
                                     e.preventDefault();
                                 }
                             },
                             false);
        let expander = commit.querySelector(".hidden-text-expander a[href]");
        if (expander) {
            expander.addEventListener("click",
                                      function (e) {
                                          insertInlinePatch(commit, sha);
                                      },
                                      false);
        }
    };
    Array.prototype.forEach.
        call(document.querySelectorAll("li.commit, tr.commit"),
             activateInlinePatch);
})();
<commit_msg>Add a namespace and a homepage on GreasyFork<commit_after>// ==UserScript==
// @name        GitHub: inline patch view
// @namespace   https://akinori.org/
// @description Clicking on a commit ID shows the patch inline.  Second click opens the link.
// @license     2-clause BSDL
// @author      Akinori MUSHA
// @include     https://github.com/*/*/commits
// @include     https://github.com/*/*/commits/*
// @include     https://github.com/*/*/pull/*
// @version     1.0.0
// @homepage    https://github.com/knu/userjs-github_inline_patch_view
// @homepage    https://greasyfork.org/scripts/17016-github-inline-patch-view
// @grant       none
// ==/UserScript==
"use strict";
(function () {
    let cloneNode = function (node) {
        let clone = document.createElement(node.tagName);
        Array.prototype.forEach.
            call(node.attributes,
                 function (attr) {
                     clone.setAttribute(attr.name, attr.value);
                 });
        return clone;
    };
    let insertInlinePatch = function (commit, sha) {
        if (commit.classList.contains("inline-patch")) {
            return false;
        }
        let url = sha.href;
        let xhr = new XMLHttpRequest();
        xhr.onload = function () {
            let patch = this.responseXML.getElementById("files");
            switch (commit.tagName) {
            case "TR":
                // Split the table to avoid CSS rule conflicts
                let container = null;
                for (let node = commit.parentNode;
                     node !== null;
                     node = node.parentNode) {
                    let clone = cloneNode(node);
                    if (container === null) {
                        // Move following siblings to a new container
                        let siblings = [];
                        for (let sibling = commit.nextSibling;
                             sibling !== null;
                             sibling = sibling.nextSibling) {
                            siblings.push(sibling);
                        }
                        siblings.forEach(function (sibling) {
                            clone.appendChild(sibling);
                        });
                    } else {
                        clone.appendChild(container);
                    }
                    container = clone;
                    if (node.tagName === "TABLE") {
                        node.parentNode.insertBefore(container, node.nextSibling);
                        patch.style.marginLeft = commit.querySelector(".commit-message").offsetLeft.toString() + "px";
                        node.parentNode.insertBefore(patch, container);
                        break;
                    }
                }
                break;
            default:
                let meta = commit.querySelector(".commit-meta");
                if (meta) {
                    meta.parentNode.appendChild(patch);
                }
            }
            commit.classList.add("inline-patch");
        };
        xhr.onerror = function () {
            console.log("Failed to load the patch from " + url);
        };
        xhr.open("GET", url);
        xhr.responseType = "document";
        xhr.send();
        return true;
    };
    let activateInlinePatch = function (commit) {
        let sha = commit.querySelector("a.sha[href*='/commit/'], a.commit-id[href*='/commit/']");
        if (!sha) {
            return;
        }
        sha.addEventListener("click",
                             function (e) {
                                 if (insertInlinePatch(commit, sha)) {
                                     e.preventDefault();
                                 }
                             },
                             false);
        let expander = commit.querySelector(".hidden-text-expander a[href]");
        if (expander) {
            expander.addEventListener("click",
                                      function (e) {
                                          insertInlinePatch(commit, sha);
                                      },
                                      false);
        }
    };
    Array.prototype.forEach.
        call(document.querySelectorAll("li.commit, tr.commit"),
             activateInlinePatch);
})();
<|endoftext|>


<commit_before>// Find urls within selected domain in posts
//

'use strict';

const _        = require('lodash');
const argparse = require('argparse');
const mongoose = require('mongoose');
const pump     = require('util').promisify(require('pump'));
const stream   = require('stream');
const URL      = require('url');

let parser = new argparse.ArgumentParser();

parser.add_argument('-d', '--db', {
  help: 'database name',
  default: 'nodeca'
});

parser.add_argument('-c', '--cutoff', {
  help: 'cutoff (days)',
  type: 'int'
});

parser.add_argument('-l', '--long', {
  help: 'hide short links (without query)',
  action: 'store_true'
});

parser.add_argument('domain', {
  help: 'domain name'
});

let args = parser.parse_args();

mongoose.Promise = Promise;

async function search() {
  const mongoose_options = {
    promiseLibrary: require('bluebird'),
    poolSize: 10,
    connectTimeoutMS: 30000,
    keepAlive: 1,

    // fix deprecation warnings appearing in mongodb driver,
    // see https://mongoosejs.com/docs/deprecations.html for details
    useNewUrlParser: true,
    useFindAndModify: false,
    useCreateIndex: true
  };

  await mongoose.connect('mongodb://localhost/' + args.db, mongoose_options);

  let Post = mongoose.model('forum.Post', new mongoose.Schema());

  let regexp_search = new RegExp('href="https?:\\/\\/[^\\/]*' + _.escapeRegExp(args.domain));

  let query = { html: regexp_search };

  if (args.cutoff) {
    let ts = Date.now() / 1000 - args.cutoff * 24 * 60 * 60;
    let min_objectid = new mongoose.Types.ObjectId(Math.floor(ts).toString(16) + '0000000000000000');

    query._id = { $gt: min_objectid };
  }

  await pump(
    Post.find(query).lean(true).cursor(),

    new stream.Writable({
      objectMode: true,
      write(post, encoding, callback) {
        let urls = post.html.match(/href="[^"]+"/g)
                     .map(href => _.unescape(href.replace(/^href="|"$/g, '')));

        urls.forEach(url => {
          let parsed = URL.parse(url, true, true);

          if (parsed.host && parsed.host.includes(args.domain)) {
            /* eslint-disable no-console */

            if (args.long) {
              if (Object.keys(parsed.query).length || parsed.hash) console.log(url, '\n');
            } else console.log(url, '\n');
          }
        });

        callback();
      }
    })
  );

  await mongoose.disconnect();
}

search();
<commit_msg>Replace pump with pipeline<commit_after>// Find urls within selected domain in posts
//

'use strict';

const _        = require('lodash');
const argparse = require('argparse');
const mongoose = require('mongoose');
const stream   = require('stream');
const pipeline = require('util').promisify(stream.pipeline);
const URL      = require('url');

let parser = new argparse.ArgumentParser();

parser.add_argument('-d', '--db', {
  help: 'database name',
  default: 'nodeca'
});

parser.add_argument('-c', '--cutoff', {
  help: 'cutoff (days)',
  type: 'int'
});

parser.add_argument('-l', '--long', {
  help: 'hide short links (without query)',
  action: 'store_true'
});

parser.add_argument('domain', {
  help: 'domain name'
});

let args = parser.parse_args();

mongoose.Promise = Promise;

async function search() {
  const mongoose_options = {
    promiseLibrary: require('bluebird'),
    poolSize: 10,
    connectTimeoutMS: 30000,
    keepAlive: 1,

    // fix deprecation warnings appearing in mongodb driver,
    // see https://mongoosejs.com/docs/deprecations.html for details
    useNewUrlParser: true,
    useFindAndModify: false,
    useCreateIndex: true
  };

  await mongoose.connect('mongodb://localhost/' + args.db, mongoose_options);

  let Post = mongoose.model('forum.Post', new mongoose.Schema());

  let regexp_search = new RegExp('href="https?:\\/\\/[^\\/]*' + _.escapeRegExp(args.domain));

  let query = { html: regexp_search };

  if (args.cutoff) {
    let ts = Date.now() / 1000 - args.cutoff * 24 * 60 * 60;
    let min_objectid = new mongoose.Types.ObjectId(Math.floor(ts).toString(16) + '0000000000000000');

    query._id = { $gt: min_objectid };
  }

  await pipeline(
    Post.find(query).lean(true).cursor(),

    new stream.Writable({
      objectMode: true,
      write(post, encoding, callback) {
        let urls = post.html.match(/href="[^"]+"/g)
                     .map(href => _.unescape(href.replace(/^href="|"$/g, '')));

        urls.forEach(url => {
          let parsed = URL.parse(url, true, true);

          if (parsed.host && parsed.host.includes(args.domain)) {
            /* eslint-disable no-console */

            if (args.long) {
              if (Object.keys(parsed.query).length || parsed.hash) console.log(url, '\n');
            } else console.log(url, '\n');
          }
        });

        callback();
      }
    })
  );

  await mongoose.disconnect();
}

search();
<|endoftext|>


<commit_before>
// limbus-buildgen - A "build anywhere" C/C++ makefile/project generator.
// Written in 2014-2016 by Jesper Oskarsson jesosk@gmail.com
//
// To the extent possible under law, the author(s) have dedicated all copyright
// and related and neighboring rights to this software to the public domain worldwide.
// This software is distributed without any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.

var should = require('should');
var util = require('./util.js');
var shell = require('./shell.js');
var minimal = require('../source/minimal-configuration');

describe('Linking', function () {
    beforeEach(function () {
        return util.beforeEach().then(function () {
            return shell.mkdir('temp/include');
        }).then(function () {
            return shell.copyFiles([
                'linked.c',
                'linked_dynamic.c',
                'source/mylibrary.c',
                'include/mylibrary.h',
                'source/mydynamiclibrary.c',
                'include/mydynamiclibrary.h',
                'math.c',
            ], 'features/linking/', 'temp/');
        });
    });

    afterEach(function () {
        return util.afterEach();
    });

    it('should compile and link correctly given several source files and includes', function () {
        return util.testConfiguration(minimal.projectWithArtifactWith({
            files: [
                'linked.c',
                'source/mylibrary.c'
            ],
            includePaths: [
                'include'
            ]
        }));
    });

    it('should pass linker flags as is', function () {
        var failFlags = {
            'application': {
                'cl': '/link /NODEFAULTLIB',
                'clang': '-nostdlib',
                'gcc': '-nostdlib'
            },
            'static-library': {
                'cl': '/SUBSYSTEM:BOOT_APPLICATIO',
                'clang': 'q',
                'gcc': 'q'
            },
            'dynamic-library': {
                'cl': '/NODEFAULTLIB',
                'clang': '-o',
                'gcc': '-o'
            }
        };
        var succeedFlags = {
            'application': {
                'cl': '/link /VERSION:1.0',
                'clang': '-s',
                'gcc': '-s'
            },
            'static-library': {
                'cl': '/WX:NO',
                'clang': 'v',
                'gcc': 'v'
            },
            'dynamic-library': {
                'cl': '/VERSION:1.0',
                'clang': '-s',
                'gcc': '-s'
            }
        };

        var linkerFlagsShouldFailForType = function(type, flags) {
            return util.writeConfiguration(minimal.projectWithArtifactWith({
                type: type,
                linkerFlags: failFlags[type][util.hostCompiler]
            }))
            .then(util.generateWithParameters())
            .then(util.build()).should.be.rejected();
        };
        var linkerFlagsShouldSucceedForType = function(type, flags) {
            return util.writeConfiguration(minimal.projectWithArtifactWith({
                type: type,
                linkerFlags: succeedFlags[type][util.hostCompiler]
            }))
            .then(util.generateWithParameters())
            .then(util.build());
        };

        return Promise.resolve().then(function () {
            return linkerFlagsShouldSucceedForType('application');
        }).then(function () {
            return linkerFlagsShouldSucceedForType('static-library');
        }).then(function () {
            return linkerFlagsShouldSucceedForType('dynamic-library');
        }).then(function () {
            return linkerFlagsShouldFailForType('application');
        }).then(function () {
            return linkerFlagsShouldFailForType('static-library');
        }).then(function () {
            return linkerFlagsShouldFailForType('dynamic-library');
        });
    });

    it('should link with libm by default', function () {
        return util.testConfiguration(minimal.projectWithArtifactWith({
            files: [
                'math.c'
            ]
        }));
    });

    it('should compile to an executable with outputName', function () {
        return util.writeConfiguration(minimal.projectWithArtifactWith({
            outputName: 'my_executable'
        }))
        .then(util.generateWithParameters())
        .then(util.build())
        .then(util.runBuiltExecutable(shell.path('./my_executable')))
        .then(util.matchOutput());
    });

    it('should compile a static library and then be able to link to it', function () {
        return util.testConfiguration({
            title: 'project',
            artifacts: [
                {
                    title: 'library',
                    type: 'static-library',
                    host: util.host,
                    files: [
                        'source/mylibrary.c'
                    ],
                    outputName: 'my_lib_name'
                },
                {
                    title: 'app',
                    type: 'application',
                    host: util.host,
                    files: [
                        'linked.c'
                    ],
                    libraries: [
                        'my_lib_name'
                    ],
                    includePaths: [
                        'include'
                    ],
                    outputName: 'app'
                }
            ]
        });
    });

    it('should compile a dynamic library and then be able to link to it', function () {
        return util.testConfiguration({
            title: 'project',
            artifacts: [
                {
                    title: 'static library',
                    type: 'static-library',
                    host: util.host,
                    files: [
                        'source/mylibrary.c'
                    ],
                    outputName: 'my_lib_name'
                },
                {
                    title: 'dynamic library',
                    type: 'dynamic-library',
                    host: util.host,
                    files: [
                        'source/mydynamiclibrary.c'
                    ],
                    libraries: [
                        'my_lib_name'
                    ],
                    outputName: 'my_dyn_lib_name'
                },
                {
                    title: 'app',
                    type: 'application',
                    host: util.host,
                    files: [
                        'linked_dynamic.c'
                    ],
                    libraries: [
                        'my_dyn_lib_name'
                    ],
                    includePaths: [
                        'include'
                    ],
                    outputName: 'app'
                }
            ]
        });
    });

    it('should search libraryPaths to find libraries to link', function () {
        return util.testConfiguration({
            title: 'project',
            artifacts: [
                {
                    title: 'library',
                    type: 'static-library',
                    host: util.host,
                    files: [
                        'source/mylibrary.c'
                    ],
                    outputName: 'my_lib_name',
                    outputPath: 'source'
                },
                {
                    title: 'app',
                    type: 'application',
                    host: util.host,
                    files: [
                        'linked.c'
                    ],
                    libraries: [
                        'my_lib_name'
                    ],
                    includePaths: [
                        'include'
                    ],
                    libraryPaths: [
                        'source'
                    ],
                    outputName: 'app'
                }
            ]
        });
    });
});
<commit_msg>Replaced linkerFlag tests with a less fragile one.<commit_after>
// limbus-buildgen - A "build anywhere" C/C++ makefile/project generator.
// Written in 2014-2016 by Jesper Oskarsson jesosk@gmail.com
//
// To the extent possible under law, the author(s) have dedicated all copyright
// and related and neighboring rights to this software to the public domain worldwide.
// This software is distributed without any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.

var should = require('should');
var util = require('./util.js');
var shell = require('./shell.js');
var minimal = require('../source/minimal-configuration');

describe('Linking', function () {
    beforeEach(function () {
        return util.beforeEach().then(function () {
            return shell.mkdir('temp/include');
        }).then(function () {
            return shell.copyFiles([
                'linked.c',
                'linked_dynamic.c',
                'source/mylibrary.c',
                'include/mylibrary.h',
                'source/mydynamiclibrary.c',
                'include/mydynamiclibrary.h',
                'math.c',
            ], 'features/linking/', 'temp/');
        });
    });

    afterEach(function () {
        return util.afterEach();
    });

    it('should compile and link correctly given several source files and includes', function () {
        return util.testConfiguration(minimal.projectWithArtifactWith({
            files: [
                'linked.c',
                'source/mylibrary.c'
            ],
            includePaths: [
                'include'
            ]
        }));
    });

    it('should link with libm by default', function () {
        return util.testConfiguration(minimal.projectWithArtifactWith({
            files: [
                'math.c'
            ]
        }));
    });

    it('should compile to an executable with outputName', function () {
        return util.writeConfiguration(minimal.projectWithArtifactWith({
            outputName: 'my_executable'
        }))
        .then(util.generateWithParameters())
        .then(util.build())
        .then(util.runBuiltExecutable(shell.path('./my_executable')))
        .then(util.matchOutput());
    });

    it('should compile a static library and then be able to link to it', function () {
        return util.testConfiguration(minimal.projectWith({
            artifacts: [
                minimal.artifactWith({
                    type: 'static-library',
                    files: ['source/mylibrary.c'],
                    outputName: 'my_lib_name'
                }),
                minimal.artifactWith({
                    files: ['linked.c'],
                    libraries: ['my_lib_name'],
                    includePaths: ['include']
                })
            ]
        }));
    });

    it('should pass linker flags as is', function () {
        var linkLibraryForCompiler = {
            gcc: '-Wl,-L. -llibrary',
            clang: '-Wl,-L. -llibrary',
            cl: 'library.lib'
        };

        return util.testConfiguration(minimal.projectWith({
            artifacts: [
                minimal.artifactWith({
                    type: 'static-library',
                    files: ['source/mylibrary.c'],
                    outputName: 'library'
                }),
                minimal.artifactWith({
                    files: ['linked.c'],
                    linkerFlags: linkLibraryForCompiler[util.hostCompiler],
                    includePaths: ['include']
                })
            ]
        }));
    });

    it('should compile a dynamic library and then be able to link to it', function () {
        return util.testConfiguration(minimal.projectWith({
            artifacts: [
                minimal.artifactWith({
                    type: 'static-library',
                    files: ['source/mylibrary.c'],
                    outputName: 'my_lib_name'
                }),
                minimal.artifactWith({
                    type: 'dynamic-library',
                    files: ['source/mydynamiclibrary.c'],
                    libraries: ['my_lib_name'],
                    outputName: 'my_dyn_lib_name'
                }),
                minimal.artifactWith({
                    files: ['linked_dynamic.c'],
                    libraries: ['my_dyn_lib_name'],
                    includePaths: ['include']
                })
            ]
        }));
    });

    it('should search libraryPaths to find libraries to link', function () {
        return util.testConfiguration(minimal.projectWith({
            artifacts: [
                minimal.artifactWith({
                    type: 'static-library',
                    files: ['source/mylibrary.c'],
                    outputName: 'my_lib_name',
                    outputPath: 'source'
                }),
                minimal.artifactWith({
                    files: ['linked.c'],
                    libraries: ['my_lib_name'],
                    includePaths: ['include'],
                    libraryPaths: ['source']
                })
            ]
        }));
    });
});
<|endoftext|>


<commit_before>'use strict';

var extend = require('extend'),
    path = require('path'),
    fs = require('fs'),
    mkdirp = require('mkdirp');

function beforeInstall(config, utils, next) {
  utils.log('► Add views dependencies... ');

  config.package = extend(true, {
    dependencies: {
      gulp: '^3.9.0',
      'gulp-rename': '^1.2.2',
      'gulp-sourcemaps': '^1.5.2',
      'gulp-uglify': '^1.2.0',
      glob: '^5.0.13',
      page: '^1.6.3'
    }
  }, config.package);

  if (config.install.plumes) {
    config.package = extend(true, {
      dependencies: {
        jquery: '^2.1.4',
        ractive: '^0.7.3',
        'ractive-require': '^0.2.4',
        plumes: '^0.2.0'
      }
    }, config.package);
  }

  utils.log('[OK]\n');

  next();
}

function afterInstall(config, utils, next) {
  var source = path.resolve(__dirname, 'resources'),
      featuresDest = path.resolve(utils.path, 'features');

  utils.log('► Create common views folders... ');

  mkdirp.sync(path.join(featuresDest, 'common/views/less'));
  mkdirp.sync(path.join(featuresDest, 'common/views/css'));
  mkdirp.sync(path.join(featuresDest, 'common/views/html'));

  mkdirp.sync(path.join(featuresDest, config.install.name, 'views/html'));
  mkdirp.sync(path.join(featuresDest, config.install.name, 'views/resources'));
  mkdirp.sync(path.join(featuresDest, config.install.name, 'views/css'));
  mkdirp.sync(path.join(featuresDest, config.install.name, 'controllers'));

  utils.log('[OK]\n');

  if (config.install.plumes) {
    utils.log('► Create common less mixins... ');

    utils.copy(path.resolve(utils.path, 'node_modules/plumes/features/common/less/common-mixins.less'), path.join(featuresDest, 'common/views/less/common-mixins.less'));
    utils.copy(path.resolve(utils.path, 'node_modules/plumes/features/common/less/common-variables.less'), path.join(featuresDest, 'common/views/less/common-variables.less'));

    utils.log('[OK]\n');
  }

  utils.log('► Create "' + config.install.name + '" view files... ');

  var featurePath = path.join(featuresDest, config.install.name),
      viewsDir = featurePath + '/views/',
      viewsPath = viewsDir + '/' + config.install.name + '-',
      htmlPath = viewsDir + 'html/' + config.install.name + '-',
      cssPath = viewsDir + 'css/' + config.install.name + '-',
      controllerPath = featurePath + '/controllers/' + config.install.name + '-',
      copyFiles = [{
        source: path.join(source, 'project-index.html'),
        destination: htmlPath + 'index.html'
      }, {
        source: path.join(source, 'project-start-mask.less'),
        destination: cssPath + 'start-mask.less'
      }, {
        source: path.join(source, 'project-index.js'),
        destination: viewsPath + 'index.js'
      }, {
        source: path.join(source, 'project-404-route.js'),
        destination: controllerPath + '404-route.js'
      }];

  copyFiles.forEach(function(file) {
    if (!fs.existsSync(file.destination)) {
      var content = utils.getContent(file.source);

      for (var item in config.install) {
        content = content.replace(new RegExp('{{' + item + '}}', 'g'), config.install[item]);
      }

      utils.putContent(content, file.destination);
    }
  });

  var fileDest = path.join(featuresDest, config.install.name, '/views/resources/favicon.ico');

  if (!fs.existsSync(fileDest)) {
    utils.copy(path.join(source, 'favicon.ico'), fileDest);
  }

  fileDest = path.join(featuresDest, config.install.name, '/views/resources/favicon.png');

  if (!fs.existsSync(fileDest)) {
    utils.copy(path.join(source, 'favicon.png'), fileDest);
  }

  utils.log('[OK]\n');

  utils.log('► Create gulpfile... ');

  utils.copy(path.join(source, 'gulpfile.js'), path.resolve(utils.path, 'gulpfile.js'));
  utils.copy(path.join(source, 'common-resources-gulpfile.js'), path.join(featuresDest, 'common/common-resources-gulpfile.js'));
  utils.copy(path.join(source, 'common-routes-gulpfile.js'), path.join(featuresDest, 'common/common-routes-gulpfile.js'));
  utils.copy(path.join(source, 'common-routes-template.js'), path.join(featuresDest, 'common/common-routes-template.js'));
  utils.copy(path.join(source, 'common-route-template.js'), path.join(featuresDest, 'common/common-route-template.js'));
  utils.copy(path.join(source, 'common-bootstrap.js'), path.join(featuresDest, 'common/views/common-bootstrap.js'));

  if (config.install.plumes) {
    utils.copy(path.join(source, 'common-plumes-gulpfile.js'), path.join(featuresDest, 'common/common-plumes-gulpfile.js'));
  }

  utils.log('[OK]\n');

  next();
}

module.exports = {
  install: [{
    type: 'confirm',
    name: 'plumes',
    message: 'Use jQuery + Ractive.js + Plumes?',
    default: true
  }],
  beforeInstall: beforeInstall,
  afterInstall: afterInstall,
  env: [{
    type: 'confirm',
    name: 'MINIFIED',
    message: 'Use minified asset files (js, css, ...)?',
    default: false
  }, {
    type: 'confirm',
    name: 'WATCHER',
    message: 'Watch files modifications (dev)?',
    default: true
  }]
};
<commit_msg>fix(views cli): update plumes to 0.2.4<commit_after>'use strict';

var extend = require('extend'),
    path = require('path'),
    fs = require('fs'),
    mkdirp = require('mkdirp');

function beforeInstall(config, utils, next) {
  utils.log('► Add views dependencies... ');

  config.package = extend(true, {
    dependencies: {
      gulp: '^3.9.0',
      'gulp-rename': '^1.2.2',
      'gulp-sourcemaps': '^1.5.2',
      'gulp-uglify': '^1.2.0',
      glob: '^5.0.13',
      page: '^1.6.3'
    }
  }, config.package);

  if (config.install.plumes) {
    config.package = extend(true, {
      dependencies: {
        jquery: '^2.1.4',
        ractive: '^0.7.3',
        'ractive-require': '^0.2.4',
        plumes: '^0.2.4'
      }
    }, config.package);
  }

  utils.log('[OK]\n');

  next();
}

function afterInstall(config, utils, next) {
  var source = path.resolve(__dirname, 'resources'),
      featuresDest = path.resolve(utils.path, 'features');

  utils.log('► Create common views folders... ');

  mkdirp.sync(path.join(featuresDest, 'common/views/less'));
  mkdirp.sync(path.join(featuresDest, 'common/views/css'));
  mkdirp.sync(path.join(featuresDest, 'common/views/html'));

  mkdirp.sync(path.join(featuresDest, config.install.name, 'views/html'));
  mkdirp.sync(path.join(featuresDest, config.install.name, 'views/resources'));
  mkdirp.sync(path.join(featuresDest, config.install.name, 'views/css'));
  mkdirp.sync(path.join(featuresDest, config.install.name, 'controllers'));

  utils.log('[OK]\n');

  if (config.install.plumes) {
    utils.log('► Create common less mixins... ');

    utils.copy(path.resolve(utils.path, 'node_modules/plumes/features/common/less/common-mixins.less'), path.join(featuresDest, 'common/views/less/common-mixins.less'));
    utils.copy(path.resolve(utils.path, 'node_modules/plumes/features/common/less/common-variables.less'), path.join(featuresDest, 'common/views/less/common-variables.less'));

    utils.log('[OK]\n');
  }

  utils.log('► Create "' + config.install.name + '" view files... ');

  var featurePath = path.join(featuresDest, config.install.name),
      viewsDir = featurePath + '/views/',
      viewsPath = viewsDir + '/' + config.install.name + '-',
      htmlPath = viewsDir + 'html/' + config.install.name + '-',
      cssPath = viewsDir + 'css/' + config.install.name + '-',
      controllerPath = featurePath + '/controllers/' + config.install.name + '-',
      copyFiles = [{
        source: path.join(source, 'project-index.html'),
        destination: htmlPath + 'index.html'
      }, {
        source: path.join(source, 'project-start-mask.less'),
        destination: cssPath + 'start-mask.less'
      }, {
        source: path.join(source, 'project-index.js'),
        destination: viewsPath + 'index.js'
      }, {
        source: path.join(source, 'project-404-route.js'),
        destination: controllerPath + '404-route.js'
      }];

  copyFiles.forEach(function(file) {
    if (!fs.existsSync(file.destination)) {
      var content = utils.getContent(file.source);

      for (var item in config.install) {
        content = content.replace(new RegExp('{{' + item + '}}', 'g'), config.install[item]);
      }

      utils.putContent(content, file.destination);
    }
  });

  var fileDest = path.join(featuresDest, config.install.name, '/views/resources/favicon.ico');

  if (!fs.existsSync(fileDest)) {
    utils.copy(path.join(source, 'favicon.ico'), fileDest);
  }

  fileDest = path.join(featuresDest, config.install.name, '/views/resources/favicon.png');

  if (!fs.existsSync(fileDest)) {
    utils.copy(path.join(source, 'favicon.png'), fileDest);
  }

  utils.log('[OK]\n');

  utils.log('► Create gulpfile... ');

  utils.copy(path.join(source, 'gulpfile.js'), path.resolve(utils.path, 'gulpfile.js'));
  utils.copy(path.join(source, 'common-resources-gulpfile.js'), path.join(featuresDest, 'common/common-resources-gulpfile.js'));
  utils.copy(path.join(source, 'common-routes-gulpfile.js'), path.join(featuresDest, 'common/common-routes-gulpfile.js'));
  utils.copy(path.join(source, 'common-routes-template.js'), path.join(featuresDest, 'common/common-routes-template.js'));
  utils.copy(path.join(source, 'common-route-template.js'), path.join(featuresDest, 'common/common-route-template.js'));
  utils.copy(path.join(source, 'common-bootstrap.js'), path.join(featuresDest, 'common/views/common-bootstrap.js'));

  if (config.install.plumes) {
    utils.copy(path.join(source, 'common-plumes-gulpfile.js'), path.join(featuresDest, 'common/common-plumes-gulpfile.js'));
  }

  utils.log('[OK]\n');

  next();
}

module.exports = {
  install: [{
    type: 'confirm',
    name: 'plumes',
    message: 'Use jQuery + Ractive.js + Plumes?',
    default: true
  }],
  beforeInstall: beforeInstall,
  afterInstall: afterInstall,
  env: [{
    type: 'confirm',
    name: 'MINIFIED',
    message: 'Use minified asset files (js, css, ...)?',
    default: false
  }, {
    type: 'confirm',
    name: 'WATCHER',
    message: 'Watch files modifications (dev)?',
    default: true
  }]
};
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import Select from './index'
import nanoId from 'nanoid'

class SelectContentManager extends Component {
  state = {
    selects: []
  }

  constructor(props) {
    super(props)

    window.botpress = window.botpress || {}
    window.botpress.pickContent = ({ contentType = null } = {}, callback) => {
      const id = nanoId()
      const rootEl = document.createElement('DIV')
      rootEl.setAttribute('data-select-content-container', id)
      document.getElementById('app').appendChild(rootEl)
      this.setState(({ selects }) => ({
        selects: [...selects, { contentType, callback, id, rootEl }]
      }))
    }
  }

  componentWillUnmount() {
    delete window.botpress.pickContent
  }

  onClose = i => () => {
    const { rootEl } = this.state.selects[i]
    this.setState(
      ({ selects }) => ({
        selects: selects.slice(0, i).concat(selects.slice(i + 1))
      }),
      () => {
        if (rootEl.parentNode) {
          rootEl.parentNode.removeChild(rootEl)
        }
      }
    )
  }

  render() {
    const { selects } = this.state
    return (

        {selects.map(({ contentType, callback, id, rootEl }, i) => (
          <Select key={id} contentType={contentType} onSelect={callback} onClose={this.onClose(i)} container={rootEl} />
        ))}

    )
  }
}

export default SelectContentManager
<commit_msg>fix(broadcast): prevent uncontroled modal closing<commit_after>import React, { Component } from 'react'
import Select from './index'
import nanoId from 'nanoid'

class SelectContentManager extends Component {
  state = {
    selects: []
  }

  constructor(props) {
    super(props)

    window.botpress = window.botpress || {}
    window.botpress.pickContent = ({ contentType = null } = {}, callback) => {
      const id = nanoId()
      const rootEl = document.createElement('DIV')
      rootEl.setAttribute('data-select-content-container', id)
      document.getElementById('app').appendChild(rootEl)
      this.setState(({ selects }) => ({
        selects: [...selects, { contentType, callback, id, rootEl }]
      }))
    }
  }

  componentWillUnmount() {
    delete window.botpress.pickContent
  }

  onClose = i => () => {
    const { rootEl } = this.state.selects[i]
    this.setState(
      ({ selects }) => ({
        selects: selects.slice(0, i).concat(selects.slice(i + 1))
      }),
      () => {
        if (rootEl.parentNode) {
          rootEl.parentNode.removeChild(rootEl)
        }
      }
    )
  }

  render() {
    const { selects } = this.state
    return (

 event.preventDefault()}>
        {selects.map(({ contentType, callback, id, rootEl }, i) => (
          <Select key={id} contentType={contentType} onSelect={callback} onClose={this.onClose(i)} container={rootEl} />
        ))}

    )
  }
}

export default SelectContentManager
<|endoftext|>