<commit_before>define(function(require, exports, module) {
    main.consumes = [
        "TestRunner", "proc", "util", "fs", "test", "language", "c9", "debugger"
    ];
    main.provides = ["test.mocha"];
    return main;

    function main(options, imports, register) {
        var TestRunner = imports.TestRunner;
        var proc = imports.proc;
        var util = imports.util;
        var test = imports.test;
        var fs = imports.fs;
        var c9 = imports.c9;
        var language = imports.language;
        var debug = imports["debugger"];

        var Coverage = test.Coverage;

        var dirname = require("path").dirname;
        var basename = require("path").basename;
        var join = require("path").join;

        /***** Initialization *****/

        var plugin = new TestRunner("Ajax.org", main.consumes, {
            caption: "Mocha Javascript Tests",
            query: {
                id: "mocha",
                label: "Mocha Test Runner",
                def: {
                    match: {
                        content: ["^\\s*describe\\("],
                        filename: [".js$"]
                    },
                    exclude: {
                        dir: ["node_modules"],
                        file: []
                    },
                    search: "*"
                }
            },
            options: [
                {
                    title: "Enable Debugger",
                    type: "checkbox-single",
                    setting: "state/test/mocha/@debug",
                    name: "debug"
                }
            ]
        });
        // var emit = plugin.getEmitter();

        var currentPty;
        var debugging;

        function load() {
            if (test.inactive)
                return;

        }

        /***** Methods *****/

        function populate(node, callback) {
            fs.readFile(node.path, function(err, contents){
                if (err) return callback(err);

                updateOutline(node, contents, callback);
            });
        }

        var wid = 0;
        function updateOutline(node, contents, callback) {
            language.getWorker(function(err, worker) {
                if (err) return callback && callback(err) || console.error(err);

                worker.emit("mocha_outline", { data: { id: ++wid, code: contents } });
                worker.on("mocha_outline_result", function onResponse(e) {
                    if (e.data.id !== wid) return;
                    worker.off("mocha_outline_result", onResponse);

                    node.importItems(e.data.result);

                    callback && callback();
                });
            });
        }

        function getTestNode(node, id, name){
            var count = 0;
            var found = (function recur(items, pname){
                for (var j, i = 0; i < items.length; i++) {
                    j = items[i];

                    if (j.type == "test") count++;
                    if (pname + j.label == name || count == id)
                        return j;

                    if (j.items) {
                        var found = recur(j.items,
                            pname + (j.type == "testset" ? j.label + " " : ""));
                        if (found) return found;
                    }
                }
            })([node], "");

            // TODO optional fallback to using id

            return found;
        }

        function getFullTestName(node){
            var name = [];

            do {
                name.unshift(node.label);
                node = node.parent;
            } while (node.type != "file");

            return name.join(" ");
        }

        var uniqueId = 0;
        function run(node, progress, options, callback){
            if (typeof options == "function")
                callback = options, options = null;

            var fileNode;
            var exec = "mocha", args = ["--reporter", "tap"];

            var allTests = node.findAllNodes("test");
            var allTestIndex = 0;

            if (node.type == "file") {
                fileNode = node;
                progress.start(allTests[allTestIndex] || node);
            }
            else {
                fileNode = node.findFileNode();
                progress.start(node.type == "test" ? node : allTests[allTestIndex]);

                args.push("--grep", util.escapeRegExp(getFullTestName(node))  // "^" +
                    + (node.type == "test" ? "$" : ""));
            }

            fileNode.ownPassed = null;
            fileNode.output = "";

            var withCodeCoverage = options && options.withCodeCoverage;
            var withDebug = options && options.debug;

            if (!withCodeCoverage && withDebug) {
                // "${debug?--nocrankshaft}",
                // "${debug?--nolazy}",
                // "${debug?`node --version | grep -vqE \"v0\\..\\.\" && echo --nodead_code_elimination`}",
                // "${debug?--debug-brk=15454}",

                args.push("--debug", "--debug-brk=15455"); // TODO extra node options

                debugging = true;
                debug.debug({
                    STARTED: 2,
                    runner: {
                        "debugger": "v8",
                        "debugport": 15455,
                        "disabled": {
                            liveUpdate: true
                        }
                    },
                    running: 2,
                    name: plugin.root.label,
                    meta: { $debugger: true }
                }, false, function(err) {
                    if (err)
                        return (debugging = false); // Either the debugger is not found or paused
                });
            }

            var path = join(c9.workspaceDir, fileNode.path);
            args.push(path);

            var coveragePath = "~/.c9/coverage/run" + (++uniqueId);
            var isWin = c9.platform == "win32";
            if (withCodeCoverage) {
                exec = "istanbul";
                args.unshift("cover", "--print", "none", "--report",
                    "lcovonly", "--dir", coveragePath,
                    isWin ? "node_modules/mocha/bin/_mocha" : "_mocha", "--");
            }
            if (isWin) {
                args.unshift("-c", '"$0" "$@"', exec);
                exec = "bash.exe";
            }

            proc.pty(exec, {
                args: args,
                cwd: dirname(path),
                fakePty: isWin
            }, function(err, pty){
                if (err) return callback(err);

                currentPty = pty;

                var lastResultNode, testCount, bailed;
                var output = "", totalTests = 0;
                pty.on("data", function(c){
                    // Log to the raw viewer
                    progress.log(fileNode, c);

                    // Number of tests
                    if (c.match(/^(\d+)\.\.(\d+)$/m)) {
                        testCount = parseInt(RegExp.$2, 10);
                    }

                    // Bail
                    else if (c.match(/^Bail out!(.*)$/m)) {
                        bailed = 3; // RegExp.$1;
                    }

                    // Update parsed nodes (set, test)
                    else if (c.match(/^(ok|not ok)\s+(\d+)\s+(.*)$/m)) {
                        var pass = RegExp.$1 == "ok" ? 1 : 0;
                        var id = RegExp.$2;
                        var name = RegExp.$3;

                        if (name.match(/"(before all|before each|after all|after each)" hook/, "$1")) {
                            name = name.replace(/"(before all|before each|after all|after each)" hook/, "$1");
                            if (!pass) bailed = 2, pass = 2;
                        }

                        // Update Node
                        var resultNode = (node.type == "test"
                            ? node
                            : getTestNode(node, id, name));

                        // I suspect this is no longer needed
                        if (!resultNode) {
                            resultNode = fileNode.addTest({
                                label: name, // TODO
                                type: "test"
                            });
                        }

                        // if (!resultNode)
                        //     resultNode = lastResultNode
                        //         || node.findAllNodes("test")[0];

                        // if (!resultNode)
                        //     return (bailed = 2); // TODO test this

                        lastResultNode = resultNode;

                        // Set Results
                        resultNode.output = output;
                        resultNode.passed = pass;
                        resultNode.annotations = null;

                        // Reset output
                        output = "";

                        // Count the tests
                        totalTests++;

                        // Update progress
                        progress.end(resultNode);

                        if (bailed) return;

                        var nextTest = allTests[++allTestIndex]; // findNextTest(resultNode);
                        if (nextTest) progress.start(nextTest);
                    }

                    // Output
                    else {
                        var stackTrace;

                        c = c.replace(/([\n\r]|^)# (?:tests|pass|fail).*[\n\r]/g, "").replace(/[ \t]+$/, "");

                        // Detect stack trace or timeout
                        if (c.match(/^\s*Error: timeout/) || c.match(/^\s+at .*:\d+:\d+\)?$/m)) {
                            if (!lastResultNode) {
                                lastResultNode = fileNode; // getTestNode(fileNode, 1);
                                fileNode.ownPassed = 2;
                                fileNode.output = c;
                                return;
                            }

                            if (c.match(/^\s*Error: timeout/)) {
                                lastResultNode.output = c;
                            }
                            else {
                                stackTrace = parseTrace(c);
                                if (stackTrace) {
                                    if (!withCodeCoverage) {
                                        if (!lastResultNode.annotations)
                                            lastResultNode.annotations = [];

                                        var path = join(c9.workspaceDir, fileNode.path);
                                        var pos = stackTrace.findPath(path);
                                        if (!pos)
                                            output += c;
                                        else {
                                            lastResultNode.annotations.push({
                                                line: pos.lineNumber,
                                                column: pos.column,
                                                message: c.trim().replace(/^\s+at/mg, "  at") //stackTrace.message
                                            });
                                        }
                                    }
                                    else
                                        lastResultNode.output += c;
                                }
                            }
                            return;
                        }

                        output += c;
                    }
                });
                pty.on("exit", function(c){
                    currentPty = null;

                    if (output) {
                        if (lastResultNode)
                            lastResultNode.output += output;
                        else
                            fileNode.output = output;

                        output = "";
                    }

                    // Special Case for Syntax Errors
                    if (fileNode.output.indexOf("SyntaxError:") > -1) {
                        var stackTrace = parseTrace(fileNode.output);
                        var filepath = isWin ? fileNode.path.replace(/\//g, "\\") : fileNode.path;
                        var rePath = new RegExp(util.escapeRegExp(filepath) + ":(\\d+)");
                        fileNode.output.match(rePath);
                        if (RegExp.$1) {
                            if (!fileNode.annotations)
                                fileNode.annotations = [];

                            var lineNumber = parseInt(RegExp.$1);
                            fileNode.annotations.push({
                                line: lineNumber,
                                column: 0,
                                message: "SyntaxError:" + stackTrace.message.split("SyntaxError:")[1]
                            });
                            fileNode.output = stackTrace.message + "\n"
                                + fileNode.path.substr(1) + ":" + lineNumber;
                            fileNode.ownPassed = 3;
                        }
                    }

                    if (testCount !== totalTests) {
                        if (!pty.isKilled)
                            fileNode.ownPassed = 2;
                    }
                    else if (bailed || pty.isKilled)
                        fileNode.ownPassed = pty.isKilled ? 3 : bailed;

                    if (withCodeCoverage && !bailed) {
                        fs.readFile(coveragePath + "/lcov.info", function(err, lcovString){
                            if (err) return done(err);

                            node.coverage = Coverage.fromLCOV(lcovString, coveragePath);

                            done();
                        });
                    }
                    else {
                        node.coverage = null;
                        done();
                    }

                    function done(err){
                        // Cleanup for before/after failure
                        allTests.forEach(function(n){
                            if (n.status != "loaded")
                                progress.end(n);
                        });

                        callback(err, node);
                    }
                });
            });

            return stop;
        }

        /**
         * This parses the different stack traces and puts them into one format
         * This borrows heavily from TraceKit (https://github.com/occ/TraceKit)
         * From: https://github.com/errwischt/stacktrace-parser/blob/master/lib/stacktrace-parser.js
         */
        var UNKNOWN_FUNCTION = '<unknown>';
        function parseTrace(stackString){
            var node  = /^\s*at (?:((?:\[object object\])?\S+(?: \[as \S+\])?) )?\(?(.*?):(\d+)(?::(\d+))?\)?\s*$/i;
            var lines = stackString.split('\n');
            var stack = [];
            var message = [];
            var parts, started;

            for (var i = 0, j = lines.length; i < j; ++i) {
                if ((parts = node.exec(lines[i]))) {
                    stack.push({
                        'file': parts[2],
                        'methodName': parts[1] || UNKNOWN_FUNCTION,
                        'lineNumber': +parts[3],
                        'column': parts[4] ? +parts[4] : null
                    });
                    started = true;
                }
                else if (!started) {
                    message.push(lines[i]);
                }
            }

            stack.message = message.join("\n");

            if ((stack.message + stack[0].file).indexOf("mocha/lib/runner.js") > -1)
                return false;

            stack.findPath = function(path, isFilename){
                for (var i = 0; i < stack.length; i++) {
                    if (stack[i].file == path)
                        return stack[i];
                }
                return isFilename ? false : this.findPath(basename(path), true);
            };

            return stack;
        }

        function stop(){
            if (currentPty) {
                currentPty.isKilled = true;
                currentPty.kill();
            }

            if (debugging)
                debug.stop();
        }

        var reStack = /([\\\/\w-_\.]+):(\d+)(?::(\d+))?/g;
        function parseLinks(strOutput){
            return strOutput.replace(reStack, function(m, name, l, c){
                name = name.replace(c9.workspaceDir, "");
                if (name.charAt(0) != "/") name = "/" + name;

                var link = name + ":" + (l - 1) + (c ? ":" + c : "");
                return "" + m + "";
            });
        }

        function findFileByPath(path) {
            var found = false;
            plugin.root.findAllNodes("file").some(function(n){
                if (n.path == path) {
                    found = n;
                    return true;
                }
            });
            return found;
        }

        function fileChange(options){
            // Update file
            var fileNode = findFileByPath(options.path);
            if (!fileNode) {
                fileNode = plugin.createFile(options.path.substr(1));
                fileNode.runner = plugin;
            }

            if (fileNode.items.length || options.runonsave)
                updateOutline(fileNode, options.value, function(){
                    options.run(fileNode); // Run file
                });
        }

        /***** Lifecycle *****/

        plugin.on("init", function() {

        });
        plugin.on("load", function() {
            // Hook into the language worker
            language.registerLanguageHandler("plugins/c9.ide.test.mocha/mocha_outline_worker");

            load();
        });
        plugin.on("unload", function() {
            currentPty = null;
            debugging = null;
        });

        /***** Register and define API *****/

        plugin.freezePublicAPI({
            /**
             *
             */
            populate: populate,

            /**
             *
             */
            parseLinks: parseLinks,

            /**
             *
             */
            fileChange: fileChange,

            /**
             *
             */
            run: run,

            /**
             *
             */
            stop: stop
        });

        register(null, {
            "test.mocha": plugin
        });
    }
});<commit_msg>Add Parallel Test Execution to the Test Panel<commit_after>define(function(require, exports, module) {
    main.consumes = [
        "TestRunner", "proc", "util", "fs", "test", "language", "c9", "debugger"
    ];
    main.provides = ["test.mocha"];
    return main;

    function main(options, imports, register) {
        var TestRunner = imports.TestRunner;
        var proc = imports.proc;
        var util = imports.util;
        var test = imports.test;
        var fs = imports.fs;
        var c9 = imports.c9;
        var language = imports.language;
        var debug = imports["debugger"];

        var Coverage = test.Coverage;

        var dirname = require("path").dirname;
        var basename = require("path").basename;
        var join = require("path").join;

        /***** Initialization *****/

        var plugin = new TestRunner("Ajax.org", main.consumes, {
            caption: "Mocha Javascript Tests",
            query: {
                id: "mocha",
                label: "Mocha Test Runner",
                def: {
                    match: {
                        content: ["^\\s*describe\\("],
                        filename: [".js$"]
                    },
                    exclude: {
                        dir: ["node_modules"],
                        file: []
                    },
                    search: "*"
                }
            },
            options: [
                {
                    title: "Enable Debugger",
                    type: "checkbox-single",
                    setting: "state/test/mocha/@debug",
                    name: "debug"
                }
            ]
        });
        // var emit = plugin.getEmitter();

        var currentPty = [];
        var debugging;

        function load() {
            if (test.inactive)
                return;

        }

        /***** Methods *****/

        function populate(node, callback) {
            fs.readFile(node.path, function(err, contents){
                if (err) return callback(err);

                updateOutline(node, contents, callback);
            });
        }

        var wid = 0;
        function updateOutline(node, contents, callback) {
            language.getWorker(function(err, worker) {
                if (err) return callback && callback(err) || console.error(err);

                var currentId = ++wid;
                worker.emit("mocha_outline", { data: { id: currentId, code: contents } });
                worker.on("mocha_outline_result", function onResponse(e) {
                    if (e.data.id !== currentId) return;

                    worker.off("mocha_outline_result", onResponse);

                    node.importItems(e.data.result);

                    callback && callback();
                });
            });
        }

        function getTestNode(node, id, name){
            var count = 0;
            var found = (function recur(items, pname){
                for (var j, i = 0; i < items.length; i++) {
                    j = items[i];

                    if (j.type == "test") count++;
                    if (pname + j.label == name || count == id)
                        return j;

                    if (j.items) {
                        var found = recur(j.items,
                            pname + (j.type == "testset" ? j.label + " " : ""));
                        if (found) return found;
                    }
                }
            })([node], "");

            // TODO optional fallback to using id

            return found;
        }

        function getFullTestName(node){
            var name = [];

            do {
                name.unshift(node.label);
                node = node.parent;
            } while (node.type != "file");

            return name.join(" ");
        }

        var uniqueId = 0;
        function run(node, progress, options, callback){
            if (typeof options == "function")
                callback = options, options = null;

            var fileNode;
            var exec = "mocha", args = ["--reporter", "tap"];

            var allTests = node.findAllNodes("test");
            var allTestIndex = 0;

            if (node.type == "file") {
                fileNode = node;
                progress.start(allTests[allTestIndex] || node);
            }
            else {
                fileNode = node.findFileNode();
                progress.start(node.type == "test" ? node : allTests[allTestIndex]);

                args.push("--grep", util.escapeRegExp(getFullTestName(node))  // "^" +
                    + (node.type == "test" ? "$" : ""));
            }

            fileNode.ownPassed = null;
            fileNode.output = "";

            var withCodeCoverage = options && options.withCodeCoverage;
            var withDebug = options && options.debug;
            var parallel = options && options.parallel;

            if (!withCodeCoverage && !parallel && withDebug) {
                // "${debug?--nocrankshaft}",
                // "${debug?--nolazy}",
                // "${debug?`node --version | grep -vqE \"v0\\..\\.\" && echo --nodead_code_elimination`}",
                // "${debug?--debug-brk=15454}",

                args.push("--debug", "--debug-brk=15455"); // TODO extra node options

                debugging = true;
                debug.debug({
                    STARTED: 2,
                    runner: {
                        "debugger": "v8",
                        "debugport": 15455,
                        "disabled": {
                            liveUpdate: true
                        }
                    },
                    running: 2,
                    name: plugin.root.label,
                    meta: { $debugger: true }
                }, false, function(err) {
                    if (err)
                        return (debugging = false); // Either the debugger is not found or paused
                });
            }

            var path = join(c9.workspaceDir, fileNode.path);
            args.push(path);

            var coveragePath = "~/.c9/coverage/run" + (++uniqueId);
            var isWin = c9.platform == "win32";
            if (withCodeCoverage) {
                exec = "istanbul";
                args.unshift("cover", "--print", "none", "--report",
                    "lcovonly", "--dir", coveragePath,
                    isWin ? "node_modules/mocha/bin/_mocha" : "_mocha", "--");
            }
            if (isWin) {
                args.unshift("-c", '"$0" "$@"', exec);
                exec = "bash.exe";
            }

            proc.pty(exec, {
                args: args,
                cwd: dirname(path),
                fakePty: isWin
            }, function(err, pty){
                if (err) return callback(err);

                var ptyId = currentPty.push(pty);

                var lastResultNode, testCount, bailed;
                var output = "", totalTests = 0;
                pty.on("data", function(c){
                    // Log to the raw viewer
                    progress.log(fileNode, c);

                    // Number of tests
                    if (c.match(/^(\d+)\.\.(\d+)$/m)) {
                        testCount = parseInt(RegExp.$2, 10);
                    }

                    // Bail
                    else if (c.match(/^Bail out!(.*)$/m)) {
                        bailed = 3; // RegExp.$1;
                    }

                    // Update parsed nodes (set, test)
                    else if (c.match(/^(ok|not ok)\s+(\d+)\s+(.*)$/m)) {
                        var pass = RegExp.$1 == "ok" ? 1 : 0;
                        var id = RegExp.$2;
                        var name = RegExp.$3;

                        if (name.match(/"(before all|before each|after all|after each)" hook/, "$1")) {
                            name = name.replace(/"(before all|before each|after all|after each)" hook/, "$1");
                            if (!pass) bailed = 2, pass = 2;
                        }

                        // Update Node
                        var resultNode = (node.type == "test"
                            ? node
                            : getTestNode(node, id, name));

                        // I suspect this is no longer needed
                        if (!resultNode) {
                            resultNode = fileNode.addTest({
                                label: name, // TODO
                                type: "test"
                            });
                        }

                        // if (!resultNode)
                        //     resultNode = lastResultNode
                        //         || node.findAllNodes("test")[0];

                        // if (!resultNode)
                        //     return (bailed = 2); // TODO test this

                        lastResultNode = resultNode;

                        // Set Results
                        resultNode.output = output;
                        resultNode.passed = pass;
                        resultNode.annotations = null;

                        // Reset output
                        output = "";

                        // Count the tests
                        totalTests++;

                        // Update progress
                        progress.end(resultNode);

                        if (bailed) return;

                        var nextTest = allTests[++allTestIndex]; // findNextTest(resultNode);
                        if (nextTest) progress.start(nextTest);
                    }

                    // Output
                    else {
                        var stackTrace;

                        c = c.replace(/([\n\r]|^)# (?:tests|pass|fail).*[\n\r]/g, "").replace(/[ \t]+$/, "");

                        // Detect stack trace or timeout
                        if (c.match(/^\s*Error: timeout/) || c.match(/^\s+at .*:\d+:\d+\)?$/m)) {
                            if (!lastResultNode) {
                                lastResultNode = fileNode; // getTestNode(fileNode, 1);
                                fileNode.ownPassed = 2;
                                fileNode.output = c;
                                return;
                            }

                            if (c.match(/^\s*Error: timeout/)) {
                                lastResultNode.output = c;
                            }
                            else {
                                stackTrace = parseTrace(c);
                                if (stackTrace) {
                                    if (!withCodeCoverage) {
                                        if (!lastResultNode.annotations)
                                            lastResultNode.annotations = [];

                                        var path = join(c9.workspaceDir, fileNode.path);
                                        var pos = stackTrace.findPath(path);
                                        if (!pos)
                                            output += c;
                                        else {
                                            lastResultNode.annotations.push({
                                                line: pos.lineNumber,
                                                column: pos.column,
                                                message: c.trim().replace(/^\s+at/mg, "  at") //stackTrace.message
                                            });
                                        }
                                    }
                                    else
                                        lastResultNode.output += c;
                                }
                            }
                            return;
                        }

                        output += c;
                    }
                });
                pty.on("exit", function(c){
                    delete currentPty[ptyId];

                    if (output) {
                        if (lastResultNode)
                            lastResultNode.output += output;
                        else
                            fileNode.output = output;

                        output = "";
                    }

                    // Special Case for Syntax Errors
                    if (fileNode.output.indexOf("SyntaxError:") > -1) {
                        var stackTrace = parseTrace(fileNode.output);
                        var filepath = isWin ? fileNode.path.replace(/\//g, "\\") : fileNode.path;
                        var rePath = new RegExp(util.escapeRegExp(filepath) + ":(\\d+)");
                        fileNode.output.match(rePath);
                        if (RegExp.$1) {
                            if (!fileNode.annotations)
                                fileNode.annotations = [];

                            var lineNumber = parseInt(RegExp.$1);
                            fileNode.annotations.push({
                                line: lineNumber,
                                column: 0,
                                message: "SyntaxError:" + stackTrace.message.split("SyntaxError:")[1]
                            });
                            fileNode.output = stackTrace.message + "\n"
                                + fileNode.path.substr(1) + ":" + lineNumber;
                            fileNode.ownPassed = 3;
                        }
                    }

                    if (testCount !== totalTests) {
                        if (!pty.isKilled)
                            fileNode.ownPassed = 2;
                    }
                    else if (bailed || pty.isKilled)
                        fileNode.ownPassed = pty.isKilled ? 3 : bailed;

                    if (withCodeCoverage && !bailed) {
                        fs.readFile(coveragePath + "/lcov.info", function(err, lcovString){
                            if (err) return done(err);

                            node.coverage = Coverage.fromLCOV(lcovString, coveragePath);

                            done();
                        });
                    }
                    else {
                        node.coverage = null;
                        done();
                    }

                    function done(err){
                        // Cleanup for before/after failure
                        allTests.forEach(function(n){
                            if (n.status != "loaded")
                                progress.end(n);
                        });

                        callback(err, node);
                    }
                });
            });

            return stop;
        }

        /**
         * This parses the different stack traces and puts them into one format
         * This borrows heavily from TraceKit (https://github.com/occ/TraceKit)
         * From: https://github.com/errwischt/stacktrace-parser/blob/master/lib/stacktrace-parser.js
         */
        var UNKNOWN_FUNCTION = '<unknown>';
        function parseTrace(stackString){
            var node  = /^\s*at (?:((?:\[object object\])?\S+(?: \[as \S+\])?) )?\(?(.*?):(\d+)(?::(\d+))?\)?\s*$/i;
            var lines = stackString.split('\n');
            var stack = [];
            var message = [];
            var parts, started;

            for (var i = 0, j = lines.length; i < j; ++i) {
                if ((parts = node.exec(lines[i]))) {
                    stack.push({
                        'file': parts[2],
                        'methodName': parts[1] || UNKNOWN_FUNCTION,
                        'lineNumber': +parts[3],
                        'column': parts[4] ? +parts[4] : null
                    });
                    started = true;
                }
                else if (!started) {
                    message.push(lines[i]);
                }
            }

            stack.message = message.join("\n");

            if ((stack.message + stack[0].file).indexOf("mocha/lib/runner.js") > -1)
                return false;

            stack.findPath = function(path, isFilename){
                for (var i = 0; i < stack.length; i++) {
                    if (stack[i].file == path)
                        return stack[i];
                }
                return isFilename ? false : this.findPath(basename(path), true);
            };

            return stack;
        }

        function stop(){
            currentPty.forEach(function(pty){
                pty.isKilled = true;
                pty.kill();
            });

            if (debugging)
                debug.stop();
        }

        var reStack = /([\\\/\w-_\.]+):(\d+)(?::(\d+))?/g;
        function parseLinks(strOutput){
            return strOutput.replace(reStack, function(m, name, l, c){
                name = name.replace(c9.workspaceDir, "");
                if (name.charAt(0) != "/") name = "/" + name;

                var link = name + ":" + (l - 1) + (c ? ":" + c : "");
                return "" + m + "";
            });
        }

        function findFileByPath(path) {
            var found = false;
            plugin.root.findAllNodes("file").some(function(n){
                if (n.path == path) {
                    found = n;
                    return true;
                }
            });
            return found;
        }

        function fileChange(options){
            // Update file
            var fileNode = findFileByPath(options.path);
            if (!fileNode) {
                fileNode = plugin.createFile(options.path.substr(1));
                fileNode.runner = plugin;
            }

            if (fileNode.items.length || options.runonsave)
                updateOutline(fileNode, options.value, function(){
                    options.run(fileNode); // Run file
                });
        }

        /***** Lifecycle *****/

        plugin.on("init", function() {

        });
        plugin.on("load", function() {
            // Hook into the language worker
            language.registerLanguageHandler("plugins/c9.ide.test.mocha/mocha_outline_worker");

            load();
        });
        plugin.on("unload", function() {
            currentPty = null;
            debugging = null;
        });

        /***** Register and define API *****/

        plugin.freezePublicAPI({
            /**
             *
             */
            populate: populate,

            /**
             *
             */
            parseLinks: parseLinks,

            /**
             *
             */
            fileChange: fileChange,

            /**
             *
             */
            run: run,

            /**
             *
             */
            stop: stop
        });

        register(null, {
            "test.mocha": plugin
        });
    }
});<|endoftext|>


<commit_before>var expect = require("expect");
var fs = require("fs");
var path = require("path");
var spawn = require("cross-spawn");

var installer = require("../src/installer");

describe("installer", function() {
  describe(".check", function() {
    context("given nothing", function() {
      it("should return undefined", function() {
        expect(installer.check()).toBe(undefined);
      });
    });

    context("given a local module", function() {
      it("should return undefined", function() {
        expect(installer.check("./foo")).toBe(undefined);
      });
    });

    context("when process.cwd() is missing package.json", function() {
      before(function() {
        this.cwd = process.cwd();

        process.chdir(__dirname);
      });

      after(function() {
        process.chdir(this.cwd);
      });

      it("should throw", function() {
        expect(function() {
          installer.check("anything");
        }).toThrow(/Cannot find module/);
      });
    });

    context("given a dependency in package.json", function() {
      it("should return undefined", function() {
        expect(installer.check("cross-spawn")).toBe(undefined);
      });
    });

    context("given a devDependency in package.json", function() {
      it("should return undefined", function() {
        expect(installer.check("expect")).toBe(undefined);
      });
    });

    context("given a linked dependency", function() {
      beforeEach(function() {
        this.lstatSync = expect.spyOn(fs, "lstatSync").andReturn({
          isSymbolicLink: function() {
            return true;
          },
        });
      });

      afterEach(function() {
        this.lstatSync.restore();
      });

      it("should return undefined", function() {
        expect(installer.check("something-linked")).toBe(undefined);
        expect(this.lstatSync.calls.length).toBe(1);
        expect(this.lstatSync.calls[0].arguments).toEqual([
          [process.cwd(), "node_modules", "something-linked"].join("/"),
        ]);
      });
    });

    context("given a global module", function() {
      it("should return undefined", function () {
        expect(installer.check("path")).toBe(undefined);
      });
    });

    context("given a module", function() {
      it("should return module", function() {
        expect(installer.check("react")).toBe("react");
      });
    });

    context("given a module/and/path", function() {
      it("should return module", function() {
        expect(installer.check("react/proptypes")).toBe("react");
      });
    });

    context("given a @namespaced/module", function() {
      it("should return @namespaced/module", function() {
        expect(installer.check("@namespaced/module")).toBe("@namespaced/module");
      });
    });

    context("given a module already installed, but not saved", function() {
      it("should return module", function() {
        expect(installer.check("yargs")).toBe("yargs");
      });
    });

    context("given a webpack !!loader/module", function() {
      it("should return undefined", function() {
        expect(installer.check("!!./css-loader/index.js',")).toBe(undefined);
      });
    })

  });

  describe(".checkBabel", function() {
    beforeEach(function() {
      this.sync = expect.spyOn(spawn, "sync").andReturn({ stdout: null });

      expect.spyOn(console, "info");
    });

    afterEach(function() {
      expect.restoreSpies();
    });

    context("when .babelrc doesn't exist", function() {
      beforeEach(function() {
        process.chdir(path.join(process.cwd(), "test"));
      });

      afterEach(function() {
        process.chdir(path.join(process.cwd(), ".."));
      });

      it("should return early", function() {
        var result = installer.checkBabel();

        expect(result).toBe(undefined);
        expect(this.sync).toNotHaveBeenCalled();
      });
    });

    context("when .babelrc exists", function() {
      beforeEach(function() {
        process.chdir(path.join(process.cwd(), "example/webpack1"));

        this.check = expect.spyOn(installer, "check").andCall(function(dep) {
          return dep;
        });

        this.install = expect.spyOn(installer, "install");
      });

      afterEach(function() {
        process.chdir(path.join(process.cwd(), "../../"));
      });

      it("should check plugins & presets", function() {
        installer.checkBabel();

        var checked = this.check.calls.map(function(call) {
          return call.arguments[0];
        });

        expect(this.check).toHaveBeenCalled();
        expect(this.check.calls.length).toEqual(6);
        expect(checked).toEqual([
          'babel-core',
          'babel-plugin-react-html-attrs',
          'babel-preset-react',
          'babel-preset-es2015',
          'babel-preset-stage-0',
          'babel-preset-react-hmre'
        ]);
      });

      it("should install missing plugins & presets", function() {
        installer.checkBabel();

        expect(this.install).toHaveBeenCalled();
        expect(this.install.calls.length).toEqual(1);
        expect(this.install.calls[0].arguments).toEqual([
          [
            'babel-core',
            'babel-plugin-react-html-attrs',
            'babel-preset-react',
            'babel-preset-es2015',
            'babel-preset-stage-0',
            'babel-preset-react-hmre'
          ],
        ]);
      });
    });
  });

  describe(".checkPackage", function() {
    beforeEach(function() {
      this.sync = expect.spyOn(spawn, "sync").andReturn({ stdout: null });

      expect.spyOn(console, "info");
    });

    afterEach(function() {
      expect.restoreSpies();
    });

    context("when package.json exists", function() {
      it("should return early", function() {
        var result = installer.checkPackage();

        expect(result).toBe(undefined);
        expect(this.sync).toNotHaveBeenCalled();
      });
    });

    context("when package.json does not exist", function() {
      beforeEach(function() {
        process.chdir(path.join(process.cwd(), "test"));
      });

      afterEach(function() {
        process.chdir(path.join(process.cwd(), ".."));
      });

      it("should initialize NPM", function() {
        installer.checkPackage();

        expect(this.sync).toHaveBeenCalled();
        expect(this.sync.calls.length).toEqual(1);
        expect(this.sync.calls[0].arguments).toEqual([
          "npm",
          ["init -y"],
          { stdio: "inherit" },
        ]);
      });
    });
  });

  describe(".install", function() {
    beforeEach(function() {
      this.sync = expect.spyOn(spawn, "sync").andReturn({ stdout: null });

      expect.spyOn(console, "info");
      expect.spyOn(console, "warn");
    });

    afterEach(function() {
      expect.restoreSpies();
    });

    context("given a falsey value", function() {
      it("should return undefined", function() {
        expect(installer.install()).toEqual(undefined);
        expect(installer.install(0)).toEqual(undefined);
        expect(installer.install(false)).toEqual(undefined);
        expect(installer.install(null)).toEqual(undefined);
        expect(installer.install("")).toEqual(undefined);
      });
    });

    context("given an empty array", function() {
      it("should return undefined", function () {
        expect(installer.install([])).toEqual(undefined);
      });
    });

    context("given a non-existant module", function() {
      beforeEach(function() {
        this.sync.andReturn({ status: 1 });
      });

      it("should attempt to install once", function() {
        installer.install("does.not.exist.jsx")

        expect(this.sync).toHaveBeenCalled();
      });

      it("should not attempt to install it again", function() {
        installer.install("does.not.exist.jsx")

        expect(this.sync).toNotHaveBeenCalled();
      });
    });

    context("given a dependency", function() {
      it("should install it", function() {
        var result = installer.install("foo");

        expect(this.sync).toHaveBeenCalled();
        expect(this.sync.calls.length).toEqual(1);
        expect(this.sync.calls[0].arguments[0]).toEqual("npm");
        expect(this.sync.calls[0].arguments[1]).toEqual(["install", "foo"]);
      });

      context("given options", function() {
        it("should pass them to child process", function() {
          var result = installer.install("foo", {
            save: true,
            saveExact: false,
            registry: "https://registry.npmjs.com/",
          });

          expect(this.sync).toHaveBeenCalled();
          expect(this.sync.calls.length).toEqual(1);
          expect(this.sync.calls[0].arguments[0]).toEqual("npm");
          expect(this.sync.calls[0].arguments[1]).toEqual([
            "install",
            "foo",
            "--save",
            "--registry='https://registry.npmjs.com/'",
          ]);
        });
      });

      context("with missing peerDependencies", function() {
        beforeEach(function() {
          this.sync.andCall(function(bin, args) {
            var dep = args[1];

            if (dep === "redbox-react") {
              return {
                stdout: new Buffer([
                  "/test",
                  "├── redbox-react@1.2.3",
                  "└── UNMET PEER DEPENDENCY react@>=0.13.2 || ^0.14.0-rc1 || ^15.0.0-rc",
                ].join("\n")),
              };
            }

            return { stdout: null };
          });
        });

        it("should install peerDependencies", function() {
          var result = installer.install("redbox-react");

          expect(this.sync.calls.length).toEqual(2);
          expect(this.sync.calls[0].arguments[1]).toEqual(["install", "redbox-react"]);
          expect(this.sync.calls[1].arguments[1]).toEqual(["install", "react@\">=0.13.2 || ^0.14.0-rc1 || ^15.0.0-rc\""]);
        });
      })
    });
  });
});
<commit_msg>Add test for installer.defaultOptions<commit_after>var expect = require("expect");
var fs = require("fs");
var path = require("path");
var spawn = require("cross-spawn");

var installer = require("../src/installer");

describe("installer", function() {
  describe(".defaultOptions", function() {
    it("should default dev to false", function() {
      expect(installer.defaultOptions.dev).toEqual(false);
    });

    it("should default peerDependencies to true", function() {
      expect(installer.defaultOptions.peerDependencies).toEqual(true);
    });
  })

  describe(".check", function() {
    context("given nothing", function() {
      it("should return undefined", function() {
        expect(installer.check()).toBe(undefined);
      });
    });

    context("given a local module", function() {
      it("should return undefined", function() {
        expect(installer.check("./foo")).toBe(undefined);
      });
    });

    context("when process.cwd() is missing package.json", function() {
      before(function() {
        this.cwd = process.cwd();

        process.chdir(__dirname);
      });

      after(function() {
        process.chdir(this.cwd);
      });

      it("should throw", function() {
        expect(function() {
          installer.check("anything");
        }).toThrow(/Cannot find module/);
      });
    });

    context("given a dependency in package.json", function() {
      it("should return undefined", function() {
        expect(installer.check("cross-spawn")).toBe(undefined);
      });
    });

    context("given a devDependency in package.json", function() {
      it("should return undefined", function() {
        expect(installer.check("expect")).toBe(undefined);
      });
    });

    context("given a linked dependency", function() {
      beforeEach(function() {
        this.lstatSync = expect.spyOn(fs, "lstatSync").andReturn({
          isSymbolicLink: function() {
            return true;
          },
        });
      });

      afterEach(function() {
        this.lstatSync.restore();
      });

      it("should return undefined", function() {
        expect(installer.check("something-linked")).toBe(undefined);
        expect(this.lstatSync.calls.length).toBe(1);
        expect(this.lstatSync.calls[0].arguments).toEqual([
          [process.cwd(), "node_modules", "something-linked"].join("/"),
        ]);
      });
    });

    context("given a global module", function() {
      it("should return undefined", function () {
        expect(installer.check("path")).toBe(undefined);
      });
    });

    context("given a module", function() {
      it("should return module", function() {
        expect(installer.check("react")).toBe("react");
      });
    });

    context("given a module/and/path", function() {
      it("should return module", function() {
        expect(installer.check("react/proptypes")).toBe("react");
      });
    });

    context("given a @namespaced/module", function() {
      it("should return @namespaced/module", function() {
        expect(installer.check("@namespaced/module")).toBe("@namespaced/module");
      });
    });

    context("given a module already installed, but not saved", function() {
      it("should return module", function() {
        expect(installer.check("yargs")).toBe("yargs");
      });
    });

    context("given a webpack !!loader/module", function() {
      it("should return undefined", function() {
        expect(installer.check("!!./css-loader/index.js',")).toBe(undefined);
      });
    })

  });

  describe(".checkBabel", function() {
    beforeEach(function() {
      this.sync = expect.spyOn(spawn, "sync").andReturn({ stdout: null });

      expect.spyOn(console, "info");
    });

    afterEach(function() {
      expect.restoreSpies();
    });

    context("when .babelrc doesn't exist", function() {
      beforeEach(function() {
        process.chdir(path.join(process.cwd(), "test"));
      });

      afterEach(function() {
        process.chdir(path.join(process.cwd(), ".."));
      });

      it("should return early", function() {
        var result = installer.checkBabel();

        expect(result).toBe(undefined);
        expect(this.sync).toNotHaveBeenCalled();
      });
    });

    context("when .babelrc exists", function() {
      beforeEach(function() {
        process.chdir(path.join(process.cwd(), "example/webpack1"));

        this.check = expect.spyOn(installer, "check").andCall(function(dep) {
          return dep;
        });

        this.install = expect.spyOn(installer, "install");
      });

      afterEach(function() {
        process.chdir(path.join(process.cwd(), "../../"));
      });

      it("should check plugins & presets", function() {
        installer.checkBabel();

        var checked = this.check.calls.map(function(call) {
          return call.arguments[0];
        });

        expect(this.check).toHaveBeenCalled();
        expect(this.check.calls.length).toEqual(6);
        expect(checked).toEqual([
          'babel-core',
          'babel-plugin-react-html-attrs',
          'babel-preset-react',
          'babel-preset-es2015',
          'babel-preset-stage-0',
          'babel-preset-react-hmre'
        ]);
      });

      it("should install missing plugins & presets", function() {
        installer.checkBabel();

        expect(this.install).toHaveBeenCalled();
        expect(this.install.calls.length).toEqual(1);
        expect(this.install.calls[0].arguments).toEqual([
          [
            'babel-core',
            'babel-plugin-react-html-attrs',
            'babel-preset-react',
            'babel-preset-es2015',
            'babel-preset-stage-0',
            'babel-preset-react-hmre'
          ],
        ]);
      });
    });
  });

  describe(".checkPackage", function() {
    beforeEach(function() {
      this.sync = expect.spyOn(spawn, "sync").andReturn({ stdout: null });

      expect.spyOn(console, "info");
    });

    afterEach(function() {
      expect.restoreSpies();
    });

    context("when package.json exists", function() {
      it("should return early", function() {
        var result = installer.checkPackage();

        expect(result).toBe(undefined);
        expect(this.sync).toNotHaveBeenCalled();
      });
    });

    context("when package.json does not exist", function() {
      beforeEach(function() {
        process.chdir(path.join(process.cwd(), "test"));
      });

      afterEach(function() {
        process.chdir(path.join(process.cwd(), ".."));
      });

      it("should initialize NPM", function() {
        installer.checkPackage();

        expect(this.sync).toHaveBeenCalled();
        expect(this.sync.calls.length).toEqual(1);
        expect(this.sync.calls[0].arguments).toEqual([
          "npm",
          ["init -y"],
          { stdio: "inherit" },
        ]);
      });
    });
  });

  describe(".install", function() {
    beforeEach(function() {
      this.sync = expect.spyOn(spawn, "sync").andReturn({ stdout: null });

      expect.spyOn(console, "info");
      expect.spyOn(console, "warn");
    });

    afterEach(function() {
      expect.restoreSpies();
    });

    context("given a falsey value", function() {
      it("should return undefined", function() {
        expect(installer.install()).toEqual(undefined);
        expect(installer.install(0)).toEqual(undefined);
        expect(installer.install(false)).toEqual(undefined);
        expect(installer.install(null)).toEqual(undefined);
        expect(installer.install("")).toEqual(undefined);
      });
    });

    context("given an empty array", function() {
      it("should return undefined", function () {
        expect(installer.install([])).toEqual(undefined);
      });
    });

    context("given a non-existant module", function() {
      beforeEach(function() {
        this.sync.andReturn({ status: 1 });
      });

      it("should attempt to install once", function() {
        installer.install("does.not.exist.jsx")

        expect(this.sync).toHaveBeenCalled();
      });

      it("should not attempt to install it again", function() {
        installer.install("does.not.exist.jsx")

        expect(this.sync).toNotHaveBeenCalled();
      });
    });

    context("given a dependency", function() {
      it("should install it", function() {
        var result = installer.install("foo");

        expect(this.sync).toHaveBeenCalled();
        expect(this.sync.calls.length).toEqual(1);
        expect(this.sync.calls[0].arguments[0]).toEqual("npm");
        expect(this.sync.calls[0].arguments[1]).toEqual(["install", "foo"]);
      });

      context("given options", function() {
        it("should pass them to child process", function() {
          var result = installer.install("foo", {
            save: true,
            saveExact: false,
            registry: "https://registry.npmjs.com/",
          });

          expect(this.sync).toHaveBeenCalled();
          expect(this.sync.calls.length).toEqual(1);
          expect(this.sync.calls[0].arguments[0]).toEqual("npm");
          expect(this.sync.calls[0].arguments[1]).toEqual([
            "install",
            "foo",
            "--save",
            "--registry='https://registry.npmjs.com/'",
          ]);
        });
      });

      context("with missing peerDependencies", function() {
        beforeEach(function() {
          this.sync.andCall(function(bin, args) {
            var dep = args[1];

            if (dep === "redbox-react") {
              return {
                stdout: new Buffer([
                  "/test",
                  "├── redbox-react@1.2.3",
                  "└── UNMET PEER DEPENDENCY react@>=0.13.2 || ^0.14.0-rc1 || ^15.0.0-rc",
                ].join("\n")),
              };
            }

            return { stdout: null };
          });
        });

        it("should install peerDependencies", function() {
          var result = installer.install("redbox-react");

          expect(this.sync.calls.length).toEqual(2);
          expect(this.sync.calls[0].arguments[1]).toEqual(["install", "redbox-react"]);
          expect(this.sync.calls[1].arguments[1]).toEqual(["install", "react@\">=0.13.2 || ^0.14.0-rc1 || ^15.0.0-rc\""]);
        });
      })
    });
  });
});
<|endoftext|>


<commit_before>const initialState = {
  isFetching: false,
  currentUserRatings: [],
  ratingsForm: {
    stars: 0,
    body: '',
  },
};
<commit_msg>Add ratingReducer skeleton<commit_after>const initialState = {
  isFetching: false,
  currentUserRatings: [],
  ratingsForm: {
    stars: 0,
    body: '',
  },
};

const ratingsReducer = (state = initialState, action) => {
  switch (action.type) {
    default:
      return state;
  }
};

export default ratingsReducer;
<|endoftext|>


<commit_before>/* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/*
 * Copyright 2013 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = function(grunt) {

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    jshint: {
      options: {
        jshintrc: 'test/jshint_config.json'
      },
      all: ['src/avm1/*.js', 'src/flash/**/*.js', 'src/swf/*.js']
    },
    exec: {
      reftest: {
        cmd: 'make -C test/ reftest'
      },
      makeref: {
        cmd: 'make -C test/ makeref'
      },
      webserver: {
        cmd: 'python utils/webserver.py'
      },
      build_web: {
        cmd: 'make -C web/ build'
      },
      build_extension: {
        cmd: 'make -C extension/firefox/ build'
      },
      build_bundle: {
        cmd: 'make -C utils/builder build'
      },
      generate_abcs: {
        cmd: 'python generate.py',
        cwd: 'src/avm2/generated'
      },
      build_playerglobal: {
        cmd: 'node build -t 9',
        cwd: 'utils/playerglobal-builder'
      },
      lint_success: {
        cmd: 'echo "SUCCESS: no lint errors"'
      }
    },
    watch: {
      web: {
        files: 'extension/firefox/**/*',
        tasks: ['build-web']
      },
      extension: {
        files: 'extension/firefox/**/*',
        tasks: ['build-extension']
      },
      abcs: {
        files: 'src/avm2/generated/**/*.as',
        tasks: ['exec:generate_abcs']
      },
      playerglobal: {
        files: ['src/flash/**/*.as'],
        tasks: ['exec:generate_playerglobal']
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-exec');

  grunt.registerTask('lint', ['jshint:all', 'exec:lint_success']);

  grunt.registerTask('update-flash-refs', function  () {
    var updateFlashRefs = require('./utils/update-flash-refs.js');
    updateFlashRefs('examples/inspector/inspector.html', 'src/flash');
    updateFlashRefs('test/harness/slave.html', 'src/flash');
  });

  grunt.registerTask('server', function () {
    var done = this.async();
    grunt.util.spawn({cmd: 'python', args: ['utils/webserver.py']}, function () {
      done();
    });
  });

  grunt.registerTask('watch-playerglobal', ['exec:build_playerglobal', 'watch:playerglobal']);

  // temporary make/python calls based on grunt-exec
  grunt.registerTask('reftest', ['exec:reftest']);
  grunt.registerTask('makeref', ['exec:makeref']);
  grunt.registerTask('build-web', ['exec:build_bundle', 'exec:build_extension', 'exec:build_web']);
  grunt.registerTask('build-extension', ['exec:build_bundle', 'exec:build_extension']);
  grunt.registerTask('build-playerglobal', ['exec:build_playerglobal']);
};
<commit_msg>Grunt tasks to build avm2<commit_after>/* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/*
 * Copyright 2013 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = function(grunt) {

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    jshint: {
      options: {
        jshintrc: 'test/jshint_config.json'
      },
      all: ['src/avm1/*.js', 'src/flash/**/*.js', 'src/swf/*.js']
    },
    exec: {
      reftest: {
        cmd: 'make -C test/ reftest'
      },
      makeref: {
        cmd: 'make -C test/ makeref'
      },
      webserver: {
        cmd: 'python utils/webserver.py'
      },
      build_web: {
        cmd: 'make -C web/ build'
      },
      build_extension: {
        cmd: 'make -C extension/firefox/ build'
      },
      build_bundle: {
        cmd: 'make -C utils/builder build'
      },
      build_avm2_ts: {
        cmd: '../../node_modules/.bin/tsc --target ES5 references.ts',
        cwd: 'src/avm2'
      },
      generate_abcs: {
        cmd: 'python generate.py',
        cwd: 'src/avm2/generated'
      },
      build_playerglobal: {
        cmd: 'node build -t 9',
        cwd: 'utils/playerglobal-builder'
      },
      lint_success: {
        cmd: 'echo "SUCCESS: no lint errors"'
      }
    },
    watch: {
      web: {
        files: 'extension/firefox/**/*',
        tasks: ['build-web']
      },
      extension: {
        files: 'extension/firefox/**/*',
        tasks: ['build-extension']
      },
      abcs: {
        files: 'src/avm2/generated/**/*.as',
        tasks: ['exec:generate_abcs']
      },
      playerglobal: {
        files: ['src/flash/**/*.as'],
        tasks: ['exec:generate_playerglobal']
      },
      avm2_ts: {
        files: ['src/avm2/*.ts'],
        tasks: ['exec:build_avm2_ts']
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-exec');

  grunt.registerTask('lint', ['jshint:all', 'exec:lint_success']);

  grunt.registerTask('update-flash-refs', function  () {
    var updateFlashRefs = require('./utils/update-flash-refs.js');
    updateFlashRefs('examples/inspector/inspector.html', 'src/flash');
    updateFlashRefs('test/harness/slave.html', 'src/flash');
  });

  grunt.registerTask('server', function () {
    var done = this.async();
    grunt.util.spawn({cmd: 'python', args: ['utils/webserver.py']}, function () {
      done();
    });
  });

  grunt.registerTask('watch-playerglobal', ['exec:build_playerglobal', 'watch:playerglobal']);
  grunt.registerTask('watch-avm2', ['exec:build_avm2_ts', 'watch:avm2_ts']);

  // temporary make/python calls based on grunt-exec
  grunt.registerTask('reftest', ['exec:reftest']);
  grunt.registerTask('makeref', ['exec:makeref']);
  grunt.registerTask('build-web', ['exec:build_avm2_ts', 'exec:build_bundle', 'exec:build_extension', 'exec:build_web']);
  grunt.registerTask('build-extension', ['exec:build_avm2_ts', 'exec:build_bundle', 'exec:build_extension']);
  grunt.registerTask('build-playerglobal', ['exec:build_avm2_ts', 'exec:build_playerglobal']);

  grunt.registerTask('avm2', ['exec:build_avm2_ts']);
};
<|endoftext|>


<commit_before>var app = angular.module('EPGViewer', ['ngRoute', 'EPGViewer.services']);

app.config(['$routeProvider', '$locationProvider', function ($routeProvider, $locationProvider) {
    $routeProvider.
    when('/', {
        controller: 'LoadTSFileCtrl',
        templateUrl: '/templates/upload_ts.html'
    }).
    when('/showEPG/:TSFileName', {
        controller: 'ShowEPGCtrl',
        resolve: {
            EPGData: function (EPGLoader) {
                return EPGLoader();
            }
        },
        templateUrl: '/templates/show_epg.html'
    }).
    otherwise({
        redirectTo: '/'
    });
}]);

app.controller('Navigator', ['$scope', 'NavigatorService',
    function ($scope, navigator_service) {
        $scope.KEY_CODE = navigator_service.KEY_CODE;

        $scope.navigate = function (keycode) {
            navigator_service.navigate(keycode);
        };
    }
]);

app.controller('LoadTSFileCtrl', ['$scope', '$location', 'EPGResource',
    function ($scope, $location, EPGResource, EPG) {
        $scope.TSFileName = '';

        $scope.loadTSFile = function () {
            $location.path('/showEPG/' + $scope.TSFileName);
        };
    }
]);

app.controller('ShowEPGCtrl', ['$scope', 'EPGData', 'EPG', 'NavigatorService',
    function ($scope, EPGData, EPG, navigator_service) {
        var get_time_labels = function (start_date, end_date) {
            var labels = [];

            var date = new Date(start_date);
            while (date < end_date) {
                var label = (date.getHours().toString().length == 2 ? date.getHours() : ('0' + date.getHours())) + ':' + (date.getMinutes().toString().length == 2 ? data.getMinutes() : ('0' + date.getMinutes()));
                var next_hour = new Date(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours() + 1);
                if (end_date < next_hour)
                    next_hour = end_date;

                labels.push({
                    'label': label,
                    'width': (next_hour - date) / (1000 * 60 * 60),
                });

                date.setHours(date.getHours() + 1);
                date.setMinutes(0);
            }

            return labels;
        };
        var set_EPG_style = function (EPG, start_date, end_date) {
            for (var i=0; i<EPG.length; ++i) {
                if (i >= $scope.EPG_first_service_shown && i < $scope.EPG_first_service_shown + $scope.EPG_max_services) {
                    EPG[i].show = true;
                } else {
                    EPG[i].show = false;
                }

                for (var j=0; j<EPG[i].events.length; ++j) {
                    var event = EPG[i].events[j];
                    var event_start_date = new Date(event.start_date);
                    var event_end_date = new Date(event.end_date);

                    if (!(event_start_date.getTime() <= start_date.getTime() && event_end_date.getTime() <= start_date.getTime()) && !(event_start_date.getTime() >= end_date.getTime() && event_end_date.getTime() >= end_date.getTime())) {
                        event.show = true;

                        var hour_from_EPG_start = (event.start_date.getTime() - $scope.EPG_start_date.getTime()) / (1000 * 60 * 60);

                        event.left = hour_from_EPG_start;
                        if (event.start_date.getTime() < $scope.EPG_start_date.getTime())
                            event.left = 0;
                        event.width = event.duration;
                        if (event.start_date.getTime() < $scope.EPG_start_date.getTime())
                            event.width -= ($scope.EPG_start_date.getTime() - event.start_date.getTime()) / (1000 * 60 * 60);
                        if (event.end_date.getTime() > $scope.EPG_end_date.getTime())
                            event.width -= (event.end_date.getTime() - $scope.EPG_end_date.getTime()) / (1000 * 60 * 60);
                    } else {
                        event.show = false;
                    }
                }
            }
        };
        var init_EPG = function () {
            $scope.EPG_length = 4; // hour(s)
            $scope.EPG_hour_width = 300;
            $scope.EPG_max_services = 5;

            $scope.EPG_start_date = new Date(EPGData.start_date);
            $scope.EPG_end_date = new Date(EPGData.start_date);
            $scope.EPG_end_date.setHours($scope.EPG_end_date.getHours() + $scope.EPG_length);
            $scope.EPG_now_date = ($scope.EPG_start_date.getMonth() + 1) + '/' + $scope.EPG_start_date.getDate();
            $scope.EPG_first_service_shown = 0;

            $scope.EPG_time_labels = get_time_labels($scope.EPG_start_date, $scope.EPG_end_date);
            $scope.EPG = EPG.generate_EPG(EPGData.services, $scope.EPG_start_date, $scope.EPG_end_date);

            $scope.update_EPG();
        };

        $scope.update_EPG = function () {
            set_EPG_style($scope.EPG, $scope.EPG_start_date, $scope.EPG_end_date);
        };
        $scope.backward = function () {
            $scope.EPG_start_date.setHours($scope.EPG_start_date.getHours() - 1);
            $scope.EPG_end_date.setHours($scope.EPG_end_date.getHours() - 1);
            $scope.EPG_now_date = ($scope.EPG_start_date.getMonth() + 1) + '/' + $scope.EPG_start_date.getDate();

            $scope.update_EPG();
        };
        $scope.forward = function () {
            $scope.EPG_start_date.setHours($scope.EPG_start_date.getHours() + 1);
            $scope.EPG_end_date.setHours($scope.EPG_end_date.getHours() + 1);
            $scope.EPG_now_date = ($scope.EPG_start_date.getMonth() + 1) + '/' + $scope.EPG_start_date.getDate();

            $scope.update_EPG();
        };
        $scope.prev_service = function () {
            $scope.EPG_first_service_shown--;
            if ($scope.EPG_first_service_shown < 0) {
                $scope.EPG_first_service_shown = 0;
            } else {
                $scope.update_EPG();
            }
        };
        $scope.next_service = function () {
            $scope.EPG_first_service_shown++;
            if ($scope.EPG_first_service_shown === $scope.EPG.length - $scope.EPG_max_services) {
                $scope.EPG_first_service_shown = $scope.EPG.length - $scope.EPG_max_services - 1;
            } else {
                $scope.update_EPG();
            }
        };

        $scope.$on('NavigatorMsg', function () {
            switch (navigator_service.keycode) {
                case navigator_service.KEY_CODE.LEFT:
                    console.log('LEFT');
                    $scope.backward();
                    break;
                case navigator_service.KEY_CODE.RIGHT:
                    console.log('RIGHT');
                    $scope.forward();
                    break;
                case navigator_service.KEY_CODE.UP:
                    console.log('UP');
                    $scope.prev_service();
                    break;
                case navigator_service.KEY_CODE.DOWN:
                    console.log('DOWN');
                    $scope.next_service();
                    break;
            }
        });

        init_EPG();
    }
]);
<commit_msg>시간 표시가 변하지 않던 오류를 해결<commit_after>var app = angular.module('EPGViewer', ['ngRoute', 'EPGViewer.services']);

app.config(['$routeProvider', '$locationProvider', function ($routeProvider, $locationProvider) {
    $routeProvider.
    when('/', {
        controller: 'LoadTSFileCtrl',
        templateUrl: '/templates/upload_ts.html'
    }).
    when('/showEPG/:TSFileName', {
        controller: 'ShowEPGCtrl',
        resolve: {
            EPGData: function (EPGLoader) {
                return EPGLoader();
            }
        },
        templateUrl: '/templates/show_epg.html'
    }).
    otherwise({
        redirectTo: '/'
    });
}]);

app.controller('Navigator', ['$scope', 'NavigatorService',
    function ($scope, navigator_service) {
        $scope.KEY_CODE = navigator_service.KEY_CODE;

        $scope.navigate = function (keycode) {
            navigator_service.navigate(keycode);
        };
    }
]);

app.controller('LoadTSFileCtrl', ['$scope', '$location', 'EPGResource',
    function ($scope, $location, EPGResource, EPG) {
        $scope.TSFileName = '';

        $scope.loadTSFile = function () {
            $location.path('/showEPG/' + $scope.TSFileName);
        };
    }
]);

app.controller('ShowEPGCtrl', ['$scope', 'EPGData', 'EPG', 'NavigatorService',
    function ($scope, EPGData, EPG, navigator_service) {
        var get_time_labels = function (start_date, end_date) {
            var labels = [];

            var date = new Date(start_date);
            while (date < end_date) {
                var label = (date.getHours().toString().length == 2 ? date.getHours() : ('0' + date.getHours())) + ':' + (date.getMinutes().toString().length == 2 ? data.getMinutes() : ('0' + date.getMinutes()));
                var next_hour = new Date(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours() + 1);
                if (end_date < next_hour)
                    next_hour = end_date;

                labels.push({
                    'label': label,
                    'width': (next_hour - date) / (1000 * 60 * 60),
                });

                date.setHours(date.getHours() + 1);
                date.setMinutes(0);
            }

            return labels;
        };
        var set_EPG_style = function (EPG, start_date, end_date) {
            for (var i=0; i<EPG.length; ++i) {
                if (i >= $scope.EPG_first_service_shown && i < $scope.EPG_first_service_shown + $scope.EPG_max_services) {
                    EPG[i].show = true;
                } else {
                    EPG[i].show = false;
                }

                for (var j=0; j<EPG[i].events.length; ++j) {
                    var event = EPG[i].events[j];
                    var event_start_date = new Date(event.start_date);
                    var event_end_date = new Date(event.end_date);

                    if (!(event_start_date.getTime() <= start_date.getTime() && event_end_date.getTime() <= start_date.getTime()) && !(event_start_date.getTime() >= end_date.getTime() && event_end_date.getTime() >= end_date.getTime())) {
                        event.show = true;

                        var hour_from_EPG_start = (event.start_date.getTime() - $scope.EPG_start_date.getTime()) / (1000 * 60 * 60);

                        event.left = hour_from_EPG_start;
                        if (event.start_date.getTime() < $scope.EPG_start_date.getTime())
                            event.left = 0;
                        event.width = event.duration;
                        if (event.start_date.getTime() < $scope.EPG_start_date.getTime())
                            event.width -= ($scope.EPG_start_date.getTime() - event.start_date.getTime()) / (1000 * 60 * 60);
                        if (event.end_date.getTime() > $scope.EPG_end_date.getTime())
                            event.width -= (event.end_date.getTime() - $scope.EPG_end_date.getTime()) / (1000 * 60 * 60);
                    } else {
                        event.show = false;
                    }
                }
            }
        };
        var init_EPG = function () {
            $scope.EPG_length = 4; // hour(s)
            $scope.EPG_hour_width = 300;
            $scope.EPG_max_services = 5;

            $scope.EPG_start_date = new Date(EPGData.start_date);
            $scope.EPG_end_date = new Date(EPGData.start_date);
            $scope.EPG_end_date.setHours($scope.EPG_end_date.getHours() + $scope.EPG_length);
            $scope.EPG_now_date = ($scope.EPG_start_date.getMonth() + 1) + '/' + $scope.EPG_start_date.getDate();
            $scope.EPG_first_service_shown = 0;

            $scope.EPG_time_labels = get_time_labels($scope.EPG_start_date, $scope.EPG_end_date);
            $scope.EPG = EPG.generate_EPG(EPGData.services, $scope.EPG_start_date, $scope.EPG_end_date);

            $scope.update_EPG();
        };

        $scope.update_EPG = function () {
            $scope.EPG_time_labels = get_time_labels($scope.EPG_start_date, $scope.EPG_end_date);
            set_EPG_style($scope.EPG, $scope.EPG_start_date, $scope.EPG_end_date);
        };
        $scope.backward = function () {
            $scope.EPG_start_date.setHours($scope.EPG_start_date.getHours() - 1);
            $scope.EPG_end_date.setHours($scope.EPG_end_date.getHours() - 1);
            $scope.EPG_now_date = ($scope.EPG_start_date.getMonth() + 1) + '/' + $scope.EPG_start_date.getDate();

            $scope.update_EPG();
        };
        $scope.forward = function () {
            $scope.EPG_start_date.setHours($scope.EPG_start_date.getHours() + 1);
            $scope.EPG_end_date.setHours($scope.EPG_end_date.getHours() + 1);
            $scope.EPG_now_date = ($scope.EPG_start_date.getMonth() + 1) + '/' + $scope.EPG_start_date.getDate();

            $scope.update_EPG();
        };
        $scope.prev_service = function () {
            $scope.EPG_first_service_shown--;
            if ($scope.EPG_first_service_shown < 0) {
                $scope.EPG_first_service_shown = 0;
            } else {
                $scope.update_EPG();
            }
        };
        $scope.next_service = function () {
            $scope.EPG_first_service_shown++;
            if ($scope.EPG_first_service_shown === $scope.EPG.length - $scope.EPG_max_services) {
                $scope.EPG_first_service_shown = $scope.EPG.length - $scope.EPG_max_services - 1;
            } else {
                $scope.update_EPG();
            }
        };

        $scope.$on('NavigatorMsg', function () {
            switch (navigator_service.keycode) {
                case navigator_service.KEY_CODE.LEFT:
                    console.log('LEFT');
                    $scope.backward();
                    break;
                case navigator_service.KEY_CODE.RIGHT:
                    console.log('RIGHT');
                    $scope.forward();
                    break;
                case navigator_service.KEY_CODE.UP:
                    console.log('UP');
                    $scope.prev_service();
                    break;
                case navigator_service.KEY_CODE.DOWN:
                    console.log('DOWN');
                    $scope.next_service();
                    break;
            }
        });

        init_EPG();
    }
]);
<|endoftext|>


<commit_before>/*global Context, getReporter */
/*exported runRules */

/**
 * Starts analysis on the current document and its subframes
 * @private
 * @param  {Object}   context  The `Context` specification object @see Context
 * @param  {Array}    options  Optional RuleOptions
 * @param  {Function} callback The function to invoke when analysis is complete; receives an array of `RuleResult`s
 */
function runRules(context, options, callback) {
	'use strict';
	context = new Context(context);

	var q = utils.queue();
	var audit = axe._audit;

	if (context.frames.length) {
		q.defer(function (done) {
			utils.collectResultsFromFrames(context, options, 'rules', null, done);
		});
	}
	q.defer(function (cb) {
		audit.run(context, options, cb);
	});
	q.then(function (data) {
		// Add wrapper object so that we may use the same "merge" function for results from inside and outside frames
		var results = utils.mergeResults(data.map(function (d) {
			return {
				results: d
			};
		}));

		// after should only run once, so ensure we are in the top level window
		if (context.initiator) {
			results = audit.after(results, options);
			results = results.map(utils.finalizeRuleResult);
		}

		callback(results);
	});
}

axe.a11yCheck = function (context, options, callback) {
	'use strict';
	if (typeof options === 'function') {
		callback = options;
		options = {};
	}

	if (!options || typeof options !== 'object') {
		options = {};
	}

	var audit = axe._audit;
	if (!audit) {
		throw new Error('No audit configured');
	}
	var reporter = getReporter(options.reporter || audit.reporter);
	runRules(context, options, function (results) {
		reporter(results, callback);
	});
};
<commit_msg>implement axe.run - WIP<commit_after>/*global Context, getReporter, Promise */
/*exported runRules */

/**
 * Starts analysis on the current document and its subframes
 * @private
 * @param  {Object}   context  The `Context` specification object @see Context
 * @param  {Array}    options  Optional RuleOptions
 * @param  {Function} callback The function to invoke when analysis is complete; receives an array of `RuleResult`s
 */
function runRules(context, options, callback) {
	'use strict';
	context = new Context(context);

	var q = utils.queue();
	var audit = axe._audit;

	if (context.frames.length) {
		q.defer(function (done) {
			utils.collectResultsFromFrames(context, options, 'rules', null, done);
		});
	}
	q.defer(function (cb) {
		audit.run(context, options, cb);
	});
	q.then(function (data) {
		// Add wrapper object so that we may use the same "merge" function for results from inside and outside frames
		var results = utils.mergeResults(data.map(function (d) {
			return {
				results: d
			};
		}));

		// after should only run once, so ensure we are in the top level window
		if (context.initiator) {
			results = audit.after(results, options);
			results = results.map(utils.finalizeRuleResult);
		}

		callback(null, results);
	});
	q.catch(callback);
}

axe._runRules = runRules;

axe.a11yCheck = function (context, options, callback) {
	'use strict';
	if (typeof options === 'function') {
		callback = options;
		options = {};
	}

	if (!options || typeof options !== 'object') {
		options = {};
	}

	var audit = axe._audit;
	if (!audit) {
		throw new Error('No audit configured');
	}
	var reporter = getReporter(options.reporter || audit.reporter);
	runRules(context, options, function (results) {
		reporter(results, callback);
	});
};

axe.run = function (arg1, arg2, arg3) {
	'use strict';
	var context, options, callback;
	var typeErr = new TypeError('axe.run arguments are invalid');

	// Determine the context
	if (typeof arg1 ===  'string' || Array.isArray(arg1) ||
		(typeof arg1 === 'object' &&
			(arg1.include !== undefined || arg1.exclude !== undefined))) {
		context = arg1;
	} else if (arg3 === undefined) {
		// Set default and shift one over
		context = document;
		arg3 = arg2;
		arg2 = arg1;
	} else {
		throw typeErr;
	}

	// Determine the options
	if (typeof arg2 === 'object') {
		options = arg2;
	} else if (arg3 === undefined) {
		// Set default and shift one over
		options = {};
		arg3 = arg2;
	} else {
		throw typeErr;
	}

	// Set the callback or noop;
	if (typeof arg3 === 'function' || arg3 === undefined) {
		callback = arg3 || function () {};
	} else {
		throw typeErr;
	}

	var p, reject, resolve;
	if (window.Promise) {
		p = new Promise(function (_resolve, _reject) {
			reject = _reject;
			resolve = _resolve;
		});
	}
	axe._runRules(context, options, function (err, result) {
		callback(err, result);

		if (err && reject) {
			reject(err);
		} else if (result && resolve) {
			resolve(result);
		}
	});

	return p;
};<|endoftext|>


<commit_before>/*global Qiniu */
/*global plupload */
/*global FileProgress */
/*global hljs */

var uploader = Qiniu.uploader({
    runtimes: 'html5,flash,html4',
    browse_button: 'pickfiles',
    container: 'container',
    drop_element: 'container',
    max_file_size: '100mb',
    flash_swf_url: 'assets/javascripts/plupload/Moxie.swf',
    dragdrop: true,
    chunk_size: '4mb',
    uptoken_url: '/uptoken?user=test',
    domain: 'http://shun.qiniudn.com/',
    // unique_names: true,
    // save_key: true,
    // x_vars: {
    //     'id': '1234',
    //     'time': function(up, file) {
    //         var time = (new Date()).getTime();
    //         // do something with 'time'
    //         return time;
    //     },
    // },
    auto_start: true,
    init: {
        'FilesAdded': function(up, files) {
            $('table').show();
            $('#success').hide();
            plupload.each(files, function(file) {
                var progress = new FileProgress(file, 'fsUploadProgress');
                progress.setStatus("等待...");
            });
        },
        'BeforeUpload': function(up, file) {
            var progress = new FileProgress(file, 'fsUploadProgress');
            var chunk_size = plupload.parseSize(this.getOption('chunk_size'));
            if (up.runtime === 'html5' && chunk_size) {
                progress.setChunkProgess(chunk_size);
            }
        },
        'UploadProgress': function(up, file) {
            var progress = new FileProgress(file, 'fsUploadProgress');
            var chunk_size = plupload.parseSize(this.getOption('chunk_size'));
            progress.setProgress(file.percent + "%", up.total.bytesPerSec, chunk_size);

        },
        'UploadComplete': function() {
            $('#success').show();
        },
        'FileUploaded': function(up, file, info) {
            var progress = new FileProgress(file, 'fsUploadProgress');
            progress.setComplete(up, info);
        },
        'Error': function(up, err, errTip) {
            $('table').show();
            var progress = new FileProgress(err.file, 'fsUploadProgress');
            progress.setError();
            progress.setStatus(errTip);
        }
        // ,
        // 'Key': function(up, file) {
        //     var key = "";
        //     // do something with key
        //     return key
        // }
    }
});

uploader.bind('FileUploaded', function() {
    console.log('hello man,a file is uploaded');
});

$(function() {
    $('#container').on(
        'dragenter',
        function(e) {
            e.preventDefault();
            $('#container').addClass('draging');
            e.stopPropagation();
        }
    ).on('drop', function(e) {
        e.preventDefault();
        $('#container').removeClass('draging');
        e.stopPropagation();
    }).on('dragleave', function(e) {
        e.preventDefault();
        $('#container').removeClass('draging');
        e.stopPropagation();
    }).on('dragover', function(e) {
        e.preventDefault();
        $('#container').addClass('draging');
        e.stopPropagation();
    });

    $('#show_code').on('click', function() {
        $('#myModal-code').modal();
        $('pre code').each(function(i, e) {
            hljs.highlightBlock(e);
        });
    });

    $('body').on('click', 'table button.btn', function() {
        $(this).parents('tr').next().toggle();
    });

    var getRotate = function(url) {
        if (!url) {
            return 0;
        }
        var arr = url.split('/');
        for (var i = 0, len = arr.length; i < len; i++) {
            if (arr[i] === 'rotate') {
                return parseInt(arr[i + 1], 10);
            }
        }
        return 0;
    };

    $('#myModal-img .modal-body-footer').find('a').on('click', function() {
        var img = $('#myModal-img').find('.modal-body img');
        var key = img.data('key');
        var oldUrl = img.attr('src');
        var originHeight = parseInt(img.data('h'), 10);
        var fopArr = [];
        var rotate = getRotate(oldUrl);
        if (!$(this).hasClass('no-disable-click')) {
            $(this).addClass('disabled').siblings().removeClass('disabled');
            if ($(this).data('imagemogr') !== 'no-rotate') {
                fopArr.push({
                    'fop': 'imageMogr2',
                    'auto-orient': true,
                    'strip': true,
                    'rotate': rotate,
                    'format': 'png'
                });
            }
        } else {
            $(this).siblings().removeClass('disabled');
            var imageMogr = $(this).data('imagemogr');
            if (imageMogr === 'left') {
                rotate = rotate - 90 < 0 ? rotate + 270 : rotate - 90;
            } else if (imageMogr === 'right') {
                rotate = rotate + 90 > 360 ? rotate - 270 : rotate + 90;
            }
            fopArr.push({
                'fop': 'imageMogr2',
                'auto-orient': true,
                'strip': true,
                'rotate': rotate,
                'format': 'png'
            });
        }

        $('#myModal-img .modal-body-footer').find('a.disabled').each(function() {

            var watermark = $(this).data('watermark');
            var imageView = $(this).data('imageview');
            var imageMogr = $(this).data('imagemogr');

            if (watermark) {
                fopArr.push({
                    fop: 'watermark',
                    mode: 1,
                    image: 'http://www.b1.qiniudn.com/images/logo-2.png',
                    dissolve: 100,
                    gravity: watermark,
                    dx: 100,
                    dy: 100
                });
            }

            if (imageView) {
                var height;
                switch (imageView) {
                    case 'large':
                        height = originHeight;
                        break;
                    case 'middle':
                        height = originHeight * 0.5;
                        break;
                    case 'small':
                        height = originHeight * 0.1;
                        break;
                    default:
                        height = originHeight;
                        break;
                }
                fopArr.push({
                    fop: 'imageView2',
                    mode: 3,
                    h: parseInt(height, 10),
                    q: 100,
                    format: 'png'
                });
            }

            if (imageMogr === 'no-rotate') {
                fopArr.push({
                    'fop': 'imageMogr2',
                    'auto-orient': true,
                    'strip': true,
                    'rotate': 0,
                    'format': 'png'
                });
            }
        });

        var newUrl = Qiniu.pipeline(fopArr, key);

        var newImg = new Image();
        img.attr('src', 'loading.gif');
        newImg.onload = function() {
            img.attr('src', newUrl);
            img.parent('a').attr('href', newUrl);
        };
        newImg.src = newUrl;
        return false;
    });

});
<commit_msg>fixed image path, add xvar collection<commit_after>/*global Qiniu */
/*global plupload */
/*global FileProgress */
/*global hljs */

var uploader = Qiniu.uploader({
    runtimes: 'html5,flash,html4',
    browse_button: 'pickfiles',
    container: 'container',
    drop_element: 'container',
    max_file_size: '100mb',
    flash_swf_url: 'assets/javascripts/plupload/Moxie.swf',
    dragdrop: true,
    chunk_size: '4mb',
    uptoken_url: '/uptoken?user=test',
    domain: 'http://shun.qiniudn.com/',
    // unique_names: true,
    // save_key: true,
    x_vars: {
        'collection': 'test'
    },
    auto_start: true,
    init: {
        'FilesAdded': function(up, files) {
            $('table').show();
            $('#success').hide();
            plupload.each(files, function(file) {
                var progress = new FileProgress(file, 'fsUploadProgress');
                progress.setStatus("等待...");
            });
        },
        'BeforeUpload': function(up, file) {
            var progress = new FileProgress(file, 'fsUploadProgress');
            var chunk_size = plupload.parseSize(this.getOption('chunk_size'));
            if (up.runtime === 'html5' && chunk_size) {
                progress.setChunkProgess(chunk_size);
            }
        },
        'UploadProgress': function(up, file) {
            var progress = new FileProgress(file, 'fsUploadProgress');
            var chunk_size = plupload.parseSize(this.getOption('chunk_size'));
            progress.setProgress(file.percent + "%", up.total.bytesPerSec, chunk_size);

        },
        'UploadComplete': function() {
            $('#success').show();
        },
        'FileUploaded': function(up, file, info) {
            var progress = new FileProgress(file, 'fsUploadProgress');
            progress.setComplete(up, info);
        },
        'Error': function(up, err, errTip) {
            $('table').show();
            var progress = new FileProgress(err.file, 'fsUploadProgress');
            progress.setError();
            progress.setStatus(errTip);
        }
        // ,
        // 'Key': function(up, file) {
        //     var key = "";
        //     // do something with key
        //     return key
        // }
    }
});

uploader.bind('FileUploaded', function() {
    console.log('hello man,a file is uploaded');
});

$(function() {
    $('#container').on(
        'dragenter',
        function(e) {
            e.preventDefault();
            $('#container').addClass('draging');
            e.stopPropagation();
        }
    ).on('drop', function(e) {
        e.preventDefault();
        $('#container').removeClass('draging');
        e.stopPropagation();
    }).on('dragleave', function(e) {
        e.preventDefault();
        $('#container').removeClass('draging');
        e.stopPropagation();
    }).on('dragover', function(e) {
        e.preventDefault();
        $('#container').addClass('draging');
        e.stopPropagation();
    });

    $('#show_code').on('click', function() {
        $('#myModal-code').modal();
        $('pre code').each(function(i, e) {
            hljs.highlightBlock(e);
        });
    });

    $('body').on('click', 'table button.btn', function() {
        $(this).parents('tr').next().toggle();
    });

    var getRotate = function(url) {
        if (!url) {
            return 0;
        }
        var arr = url.split('/');
        for (var i = 0, len = arr.length; i < len; i++) {
            if (arr[i] === 'rotate') {
                return parseInt(arr[i + 1], 10);
            }
        }
        return 0;
    };

    $('#myModal-img .modal-body-footer').find('a').on('click', function() {
        var img = $('#myModal-img').find('.modal-body img');
        var key = img.data('key');
        var oldUrl = img.attr('src');
        var originHeight = parseInt(img.data('h'), 10);
        var fopArr = [];
        var rotate = getRotate(oldUrl);
        if (!$(this).hasClass('no-disable-click')) {
            $(this).addClass('disabled').siblings().removeClass('disabled');
            if ($(this).data('imagemogr') !== 'no-rotate') {
                fopArr.push({
                    'fop': 'imageMogr2',
                    'auto-orient': true,
                    'strip': true,
                    'rotate': rotate,
                    'format': 'png'
                });
            }
        } else {
            $(this).siblings().removeClass('disabled');
            var imageMogr = $(this).data('imagemogr');
            if (imageMogr === 'left') {
                rotate = rotate - 90 < 0 ? rotate + 270 : rotate - 90;
            } else if (imageMogr === 'right') {
                rotate = rotate + 90 > 360 ? rotate - 270 : rotate + 90;
            }
            fopArr.push({
                'fop': 'imageMogr2',
                'auto-orient': true,
                'strip': true,
                'rotate': rotate,
                'format': 'png'
            });
        }

        $('#myModal-img .modal-body-footer').find('a.disabled').each(function() {

            var watermark = $(this).data('watermark');
            var imageView = $(this).data('imageview');
            var imageMogr = $(this).data('imagemogr');

            if (watermark) {
                fopArr.push({
                    fop: 'watermark',
                    mode: 1,
                    image: 'http://www.b1.qiniudn.com/images/logo-2.png',
                    dissolve: 100,
                    gravity: watermark,
                    dx: 100,
                    dy: 100
                });
            }

            if (imageView) {
                var height;
                switch (imageView) {
                    case 'large':
                        height = originHeight;
                        break;
                    case 'middle':
                        height = originHeight * 0.5;
                        break;
                    case 'small':
                        height = originHeight * 0.1;
                        break;
                    default:
                        height = originHeight;
                        break;
                }
                fopArr.push({
                    fop: 'imageView2',
                    mode: 3,
                    h: parseInt(height, 10),
                    q: 100,
                    format: 'png'
                });
            }

            if (imageMogr === 'no-rotate') {
                fopArr.push({
                    'fop': 'imageMogr2',
                    'auto-orient': true,
                    'strip': true,
                    'rotate': 0,
                    'format': 'png'
                });
            }
        });

        var newUrl = Qiniu.pipeline(fopArr, key);

        var newImg = new Image();
        img.attr('src', 'assets/images/loading.gif');
        newImg.onload = function() {
            img.attr('src', newUrl);
            img.parent('a').attr('href', newUrl);
        };
        newImg.src = newUrl;
        return false;
    });

});
<|endoftext|>