<commit_before>/*global module, require*/
var util = require('util'),
    _ = require('underscore'),
    step = require('step'),
    uglify = require('uglify-js'),
    error = require('../error'),
    memoizeAsyncAccessor = require('../memoizeAsyncAccessor'),
    relations = require('../relations'),
    UrlMap = require('../UrlMap'),
    Base = require('./Base').Base,
    deepClone = require('../deepClone'),
    fileUtils = require('../fileUtils');

function JavaScript(config) {
    Base.call(this, config);
}

util.inherits(JavaScript, Base);

_.extend(JavaScript.prototype, {
    contentType: 'application/javascript', // TODO: Double check that this is everyone's recommended value

    defaultExtension: 'js',

    isPretty: false,

    getParseTree: memoizeAsyncAccessor('parseTree', function (cb) {
        var that = this;
        this.getDecodedSrc(error.passToFunction(cb, function (decodedSrc) {
            cb(null, uglify.parser.parse(decodedSrc));
        }));
    }),

    minify: function (cb) {
        this.isPretty = false;
        process.nextTick(cb);
    },

    prettyPrint: function (cb) {
        this.isPretty = true;
        process.nextTick(cb);
    },

    getText: function (cb) {
        var that = this;
        this.getParseTree(error.passToFunction(cb, function (parseTree) {
            if (that.isMinified) {
                parseTree = uglify.uglify.ast_squeeze(uglify.uglify.ast_mangle(parseTree), {no_warnings: true});
            }
            cb(null, uglify.uglify.gen_code(parseTree, that.isPretty));
        }));
    },

    getOriginalRelations: memoizeAsyncAccessor('originalRelations', function (cb) {
        var that = this;
        this.getParseTree(error.passToFunction(cb, function (parseTree) {
            cb = error.onlyCallOnce(cb);

            var stack = [],
                originalRelations = [];

            function traverse(node) {
                if (node[0] === 'stat' && Array.isArray(node[1]) &&
                    node[1][0] === 'call' && Array.isArray(node[1][1]) && node[1][1][0] === 'dot' &&
                    Array.isArray(node[1][1][1]) && node[1][1][1][0] === 'name' && node[1][1][1][1] === 'one') {

                    if (/^(?:lazyInlude|include)$/.test(node[1][1][2])) {
                        if (Array.isArray(node[1][2]) && node[1][2].length === 1 &&
                            Array.isArray(node[1][2][0]) && node[1][2][0][0] === 'string') {

                            originalRelations.push(new relations['JavaScript' + (node[1][1][2] === 'include' ? 'Static' : 'Lazy') + 'Include']({
                                from: that,
                                node: node,
                                parentNode: stack[stack.length - 1],
                                to: node[1][2][0][1]
                            }));
                        } else {
                            return cb(new Error("Invalid one.include syntax"));
                        }
                    }
                } else if (node[0] === 'call' && Array.isArray(node[1]) && node[1][0] === 'dot' &&
                           Array.isArray(node[1][1]) && node[1][1][0] === 'name' && node[1][1][1] === 'one' &&
                           node[1][2] === 'getStaticUrl') {

                    if (node.length >= 3 && Array.isArray(node[2]) && Array.isArray(node[2][0]) &&
                        node[2][0][0] === 'string') {
                        originalRelations.push(new relations.JavaScriptStaticUrl({
                            from: that,
                            urlMap: new UrlMap({
                                parentNode: stack[stack.length - 1],
                                node: node,
                                wildCardValueAsts: node[2].slice(1),
                                originalUrl: node[2][0][1]
                            }),
                            to: node[2][0][1]
                        }));
                    } else if (node.length === 3 && Array.isArray(node[2]) && Array.isArray(node[2][0]) && node[2][0][0] === 'sub') {
                        // Result of UrlMap.toExpressionAst
                        var urlMap = UrlMap.fromExpressionAst(node[2][0]);
                        urlMap.getReachableUrls().forEach(function (reachableUrl) {
                            originalRelations.push(new relations.JavaScriptStaticUrl({
                                from: that,
                                to: reachableUrl,
                                parentNode: stack[stack.length - 1],
                                node: node,
                                urlMap: urlMap
                            }));
                        });
                    } else {
                        return cb(new Error("Invalid one.getStaticUrl syntax: " + uglify.uglify.gen_code(node)));
                    }
                } else if (node[0] === 'if' && node[1][0] === 'dot' &&
                           node[1][1][0] === 'name' && node[1][1][1] === 'one') {
                    originalRelations.push(new relations.JavaScriptConditionalBlock({
                        from: that,
                        parentNode: stack[stack.length - 1],
                        node: node,
                        environment: node[1][2],
                        to: {
                            type: 'JavaScript',
                            rawSrc: true, // FIXME
                            parseTree: deepClone(node[2])
                        }
                    }));
                }

                for (var i=0 ; i < node.length ; i++) {
                    if (Array.isArray(node[i])) {
                        stack.push(node);
                        traverse(node[i]);
                        stack.pop();
                    }
                }
            }
            traverse(parseTree);
            cb(null, originalRelations);
        }));
    }),

    attachRelation: function (relation, position, adjacentRelation) {
        position = position || 'after';
        _.extend(relation, {
            from: this,
            parentNode: adjacentRelation.parentNode
        });
        if (relation.type === 'JavaScriptStaticUrl') {
            if (!adjacentRelation) {
                throw new Error("Cannot attach a JavaScriptStaticUrl relation without an adjacent relation");
            }
            relation.urlMap = adjacentRelation.urlMap;
            relation.originalUrl = fileUtils.inferRelativeUrl(relation.urlMap.originalUrl, relation.to.url);
            relation.urlMap.addExpandedUrl(relation.originalUrl);
        } else {
            relation.node = relation.createNode(this.parseTree);
            var i = relation.parentNode.indexOf(adjacentRelation.node) + (position === 'after' ? 1 : 0);
            relation.parentNode.splice(i, 0, relation.node);
        }
    },

    detachRelation: function (relation) {
        if (relation.type === 'JavaScriptStaticUrl') {
            relation.urlMap.removeExpandedUrl(relation.originalUrl);
        } else {
            relation.parentNode.splice(relation.parentNode.indexOf(relation.node), 1);
            delete relation.node;
            delete relation.parentNode;
        }
    }
});

JavaScript.makeBundle = function (javaScripts, cb) {
    step(
        function () {
            var group = this.group();
            javaScripts.forEach(function (javaScript) {
                javaScript.getParseTree(group());
            });
        },
        error.passToFunction(cb, function (parseTrees) {
            cb(null, new JavaScript({
                parseTree: [
                    'toplevel',
                    [].concat.apply([], parseTrees.map(function (parseTree) {
                        return parseTree[1];
                    }))
                ]
            }));
        })
    );
};

exports.JavaScript = JavaScript;
<commit_msg>Experimental: Turned UglifyJS on again.<commit_after>/*global module, require*/
var util = require('util'),
    _ = require('underscore'),
    step = require('step'),
    uglify = require('uglify-js'),
    error = require('../error'),
    memoizeAsyncAccessor = require('../memoizeAsyncAccessor'),
    relations = require('../relations'),
    UrlMap = require('../UrlMap'),
    Base = require('./Base').Base,
    deepClone = require('../deepClone'),
    fileUtils = require('../fileUtils');

function JavaScript(config) {
    Base.call(this, config);
}

util.inherits(JavaScript, Base);

_.extend(JavaScript.prototype, {
    contentType: 'application/javascript', // TODO: Double check that this is everyone's recommended value

    defaultExtension: 'js',

    isPretty: false,

    getParseTree: memoizeAsyncAccessor('parseTree', function (cb) {
        var that = this;
        this.getDecodedSrc(error.passToFunction(cb, function (decodedSrc) {
            cb(null, uglify.parser.parse(decodedSrc));
        }));
    }),

    minify: function (cb) {
        this.isPretty = false;
        this.isMinified = true;
        process.nextTick(cb);
    },

    prettyPrint: function (cb) {
        this.isPretty = true;
        process.nextTick(cb);
    },

    getText: function (cb) {
        var that = this;
        that.getParseTree(error.passToFunction(cb, function (parseTree) {
            if (that.isMinified) {
                parseTree = uglify.uglify.ast_squeeze(uglify.uglify.ast_mangle(parseTree), {no_warnings: true});
            }
            cb(null, uglify.uglify.gen_code(parseTree, that.isPretty));
        }));
    },

    getOriginalRelations: memoizeAsyncAccessor('originalRelations', function (cb) {
        var that = this;
        this.getParseTree(error.passToFunction(cb, function (parseTree) {
            cb = error.onlyCallOnce(cb);

            var stack = [],
                originalRelations = [];

            function traverse(node) {
                if (node[0] === 'stat' && Array.isArray(node[1]) &&
                    node[1][0] === 'call' && Array.isArray(node[1][1]) && node[1][1][0] === 'dot' &&
                    Array.isArray(node[1][1][1]) && node[1][1][1][0] === 'name' && node[1][1][1][1] === 'one') {

                    if (/^(?:lazyInlude|include)$/.test(node[1][1][2])) {
                        if (Array.isArray(node[1][2]) && node[1][2].length === 1 &&
                            Array.isArray(node[1][2][0]) && node[1][2][0][0] === 'string') {

                            originalRelations.push(new relations['JavaScript' + (node[1][1][2] === 'include' ? 'Static' : 'Lazy') + 'Include']({
                                from: that,
                                node: node,
                                parentNode: stack[stack.length - 1],
                                to: node[1][2][0][1]
                            }));
                        } else {
                            return cb(new Error("Invalid one.include syntax"));
                        }
                    }
                } else if (node[0] === 'call' && Array.isArray(node[1]) && node[1][0] === 'dot' &&
                           Array.isArray(node[1][1]) && node[1][1][0] === 'name' && node[1][1][1] === 'one' &&
                           node[1][2] === 'getStaticUrl') {

                    if (node.length >= 3 && Array.isArray(node[2]) && Array.isArray(node[2][0]) &&
                        node[2][0][0] === 'string') {
                        originalRelations.push(new relations.JavaScriptStaticUrl({
                            from: that,
                            urlMap: new UrlMap({
                                parentNode: stack[stack.length - 1],
                                node: node,
                                wildCardValueAsts: node[2].slice(1),
                                originalUrl: node[2][0][1]
                            }),
                            to: node[2][0][1]
                        }));
                    } else if (node.length === 3 && Array.isArray(node[2]) && Array.isArray(node[2][0]) && node[2][0][0] === 'sub') {
                        // Result of UrlMap.toExpressionAst
                        var urlMap = UrlMap.fromExpressionAst(node[2][0]);
                        urlMap.getReachableUrls().forEach(function (reachableUrl) {
                            originalRelations.push(new relations.JavaScriptStaticUrl({
                                from: that,
                                to: reachableUrl,
                                parentNode: stack[stack.length - 1],
                                node: node,
                                urlMap: urlMap
                            }));
                        });
                    } else {
                        return cb(new Error("Invalid one.getStaticUrl syntax: " + uglify.uglify.gen_code(node)));
                    }
                } else if (node[0] === 'if' && node[1][0] === 'dot' &&
                           node[1][1][0] === 'name' && node[1][1][1] === 'one') {
                    originalRelations.push(new relations.JavaScriptConditionalBlock({
                        from: that,
                        parentNode: stack[stack.length - 1],
                        node: node,
                        environment: node[1][2],
                        to: {
                            type: 'JavaScript',
                            rawSrc: true, // FIXME
                            parseTree: deepClone(node[2])
                        }
                    }));
                }

                for (var i=0 ; i < node.length ; i++) {
                    if (Array.isArray(node[i])) {
                        stack.push(node);
                        traverse(node[i]);
                        stack.pop();
                    }
                }
            }
            traverse(parseTree);
            cb(null, originalRelations);
        }));
    }),

    attachRelation: function (relation, position, adjacentRelation) {
        position = position || 'after';
        _.extend(relation, {
            from: this,
            parentNode: adjacentRelation.parentNode
        });
        if (relation.type === 'JavaScriptStaticUrl') {
            if (!adjacentRelation) {
                throw new Error("Cannot attach a JavaScriptStaticUrl relation without an adjacent relation");
            }
            relation.urlMap = adjacentRelation.urlMap;
            relation.originalUrl = fileUtils.inferRelativeUrl(relation.urlMap.originalUrl, relation.to.url);
            relation.urlMap.addExpandedUrl(relation.originalUrl);
        } else {
            relation.node = relation.createNode(this.parseTree);
            var i = relation.parentNode.indexOf(adjacentRelation.node) + (position === 'after' ? 1 : 0);
            relation.parentNode.splice(i, 0, relation.node);
        }
    },

    detachRelation: function (relation) {
        if (relation.type === 'JavaScriptStaticUrl') {
            relation.urlMap.removeExpandedUrl(relation.originalUrl);
        } else {
            relation.parentNode.splice(relation.parentNode.indexOf(relation.node), 1);
            delete relation.node;
            delete relation.parentNode;
        }
    }
});

JavaScript.makeBundle = function (javaScripts, cb) {
    step(
        function () {
            var group = this.group();
            javaScripts.forEach(function (javaScript) {
                javaScript.getParseTree(group());
            });
        },
        error.passToFunction(cb, function (parseTrees) {
            cb(null, new JavaScript({
                parseTree: [
                    'toplevel',
                    [].concat.apply([], parseTrees.map(function (parseTree) {
                        return parseTree[1];
                    }))
                ]
            }));
        })
    );
};

exports.JavaScript = JavaScript;
<|endoftext|>


<commit_before>var globalFraymotifCreator = new FraymotifCreator(null);
loadNavbar();
var curSessionGlobalVar;

function makeFraymotif(){
		curSessionGlobalVar = new Session(Math.seed);
		var tier = $('[name="tier"] option:selected');
		var aspects = [];
		$('#aspects :selected').each(function(i, selected){
			aspects.push($(selected).text());
		});
		//in real sim, won't be shuffled, first player will be first element
		var players = createPlayersFromAspects(aspects);
		var fraymotif = globalFraymotifCreator.makeFraymotif(shuffle(players), tier.val());
		$("#fraymotifs").append("
" + fraymotif);
}

function createPlayersFromAspects(aspects){
	var ret = [];
	available_classes = classes; //allow all classes again for next fraymotif.
	for(var i = 0; i< aspects.length; i++){
		ret.push(getPlayerForAspect(aspects[i]));
	}
	return ret;
}

function getPlayerForAspect(aspect){
	var ret = randomPlayer(curSessionGlobalVar)
	ret.aspect = aspect;
	return ret;
}

function shuffle(array) {
	  var currentIndex = array.length, temporaryValue, randomIndex;

	  // While there remain elements to shuffle...
	  while (0 !== currentIndex) {

		// Pick a remaining element...
		randomIndex = Math.floor(Math.random() * currentIndex);
		currentIndex -= 1;

		// And swap it with the current element.
		temporaryValue = array[currentIndex];
		array[currentIndex] = array[randomIndex];
		array[randomIndex] = temporaryValue;
	}

return array;
}<commit_msg>okay, what now<commit_after>var globalFraymotifCreator = new FraymotifCreator(null);
loadNavbar();
var curSessionGlobalVar;
var fraymotifSandBoxes = [];

function makeFraymotif(){
		curSessionGlobalVar = new Session(Math.seed);
		var tier = $('[name="tier"] option:selected');
		var aspects = [];
		$('#aspects :selected').each(function(i, selected){
			aspects.push($(selected).text());
		});
		//in real sim, won't be shuffled, first player will be first element
		var players = createPlayersFromAspects(aspects);
		var fraymotif = globalFraymotifCreator.makeFraymotif(shuffle(players), tier.val());
		$("#fraymotifs").append("
" + fraymotif);
		fraymotifSandBoxes.push(new fraymotifSandBox(fraymotif, players));
}

function createPlayersFromAspects(aspects){
	var ret = [];
	available_classes = classes; //allow all classes again for next fraymotif.
	for(var i = 0; i< aspects.length; i++){
		ret.push(getPlayerForAspect(aspects[i]));
	}
	return ret;
}

function getPlayerForAspect(aspect){
	var ret = randomPlayer(curSessionGlobalVar)
	ret.aspect = aspect;
	return ret;
}

function shuffle(array) {
	  var currentIndex = array.length, temporaryValue, randomIndex;

	  // While there remain elements to shuffle...
	  while (0 !== currentIndex) {

		// Pick a remaining element...
		randomIndex = Math.floor(Math.random() * currentIndex);
		currentIndex -= 1;

		// And swap it with the current element.
		temporaryValue = array[currentIndex];
		array[currentIndex] = array[randomIndex];
		array[randomIndex] = temporaryValue;
	}

return array;
}

function fraymotifSandBox(fraymotif, players){
	this.fraymotif = fraymotif;
	this.players = players;
}<|endoftext|>


<commit_before>var util = require('util'),
    _ = require('underscore'),
    uglify = require('uglify-js'),
    passError = require('../util/passError'),
    memoizeAsyncAccessor = require('../util/memoizeAsyncAccessor'),
    relations = require('../relations'),
    Text = require('./Text'),
    deepCopy = require('../util/deepCopy'),
    urlTools = require('../util/urlTools');

function JavaScript(config) {
    Text.call(this, config);
}

util.inherits(JavaScript, Text);

_.extend(JavaScript.prototype, {
    contentType: 'application/javascript', // TODO: Double check that this is everyone's recommended value

    defaultExtension: '.js',

    isPretty: false,

    getParseTree: memoizeAsyncAccessor('parseTree', function (cb) {
        var that = this;
        this.getDecodedSrc(passError(cb, function (decodedSrc) {
            var parseTree;
            try {
                parseTree = uglify.parser.parse(decodedSrc);
            } catch (e) {
                return cb(new Error("Parse error in " + (that.url || "inline script") + "\n" +
                                    e.message + " (line " + e.line + ", col " + e.col + ")"));
            }
            cb(null, parseTree);
        }));
    }),

    isEmpty: function (cb) {
        this.getParseTree(passError(cb, function (parseTree) {
            cb(null, parseTree[1].length === 0);
        }));
    },

    minify: function (cb) {
        this.isPretty = false;
        process.nextTick(cb);
    },

    prettyPrint: function (cb) {
        this.isPretty = true;
        process.nextTick(cb);
    },

    getText: function (cb) {
        var that = this;
        that.getParseTree(passError(cb, function (parseTree) {
            cb(null, uglify.uglify.gen_code(parseTree, {beautify: that.isPretty}));
        }));
    },

    getOriginalRelations: memoizeAsyncAccessor('originalRelations', function (cb) {
        var that = this;
        this.getParseTree(passError(cb, function (parseTree) {
            var stack = [],
                originalRelations = [],
                firstErrorOrNull = null;

            function extractStringNodes(arrayOrStringOrObjectAst, errorMessage) {
                var stringNodes = [];

                if (arrayOrStringOrObjectAst[0] === 'string') {
                    stringNodes = [arrayOrStringOrObjectAst];
                } else if (arrayOrStringOrObjectAst[0] === 'array' && arrayOrStringOrObjectAst[1].every(function (node) {return node[0] === 'string';})) {
                    stringNodes = arrayOrStringOrObjectAst[1];
                } else if (arrayOrStringOrObjectAst[0] === 'object' && arrayOrStringOrObjectAst[1].every(function (keyValue) {return keyValue[1][0] === 'string';})) {
                    stringNodes = arrayOrStringOrObjectAst[1].map(function (keyValue) {
                        return keyValue[1];
                    });
                } else {
                    firstErrorOrNull = firstErrorOrNull || new Error(errorMessage + ': first argument must be string or array of strings: ' + JSON.stringify(arrayOrStringOrObjectAst));
                }
                return stringNodes;
            }

            function traverse(node) {
                if (node[0] === 'stat' && Array.isArray(node[1]) &&
                    node[1][0] === 'call' && Array.isArray(node[1][1]) && node[1][1][0] === 'dot' &&
                    Array.isArray(node[1][1][1]) && node[1][1][1][0] === 'name' && node[1][1][1][1] === 'one' && node[1][1][2] === 'include') {
                    if (Array.isArray(node[1][2]) && node[1][2].length === 1 &&
                        Array.isArray(node[1][2][0]) && node[1][2][0][0] === 'string') {

                        originalRelations.push(new relations.JavaScriptOneInclude({
                            from: that,
                            to: node[1][2][0][1],
                            node: node,
                            parentNode: stack[stack.length - 1]
                        }));
                    } else {
                        firstErrorOrNull = firstErrorOrNull || new Error("Invalid one.include syntax");
                    }
                } else if (node[0] === 'call' && Array.isArray(node[1]) && node[1][0] === 'dot' &&
                           Array.isArray(node[1][1]) && node[1][1][0] === 'name' && node[1][1][1] === 'one' &&
                           node[1][2] === 'getStaticUrl') {
                    if (node.length >= 3 && Array.isArray(node[2]) && Array.isArray(node[2][0]) &&
                        node[2][0][0] === 'string') {

                        originalRelations.push(new relations.JavaScriptOneGetStaticUrl({
                            from: that,
                            to: node[2][0][1],
                            urlMap: new relations.JavaScriptOneGetStaticUrl.UrlMap({
                                parentNode: stack[stack.length - 1],
                                node: node,
                                wildCardValueASTs: node[2].slice(1),
                                originalUrl: node[2][0][1]
                            })
                        }));
                    } else if (node.length === 3 && Array.isArray(node[2]) && Array.isArray(node[2][0]) && node[2][0][0] === 'sub') {
                        // Result of JavaScriptOneGetStaticUrl.UrlMap.toExpressionAST
                        var urlMap = relations.JavaScriptOneGetStaticUrl.UrlMap.fromExpressionAST(node[2][0]);
                        urlMap.node = node;
                        urlMap.expandedUrls.forEach(function (expandedUrl) {
                            var mappedUrl = urlMap.expandedUrlMapping[expandedUrl] || expandedUrl;
                            originalRelations.push(new relations.JavaScriptOneGetStaticUrl({
                                from: that,
                                to: mappedUrl,
                                originalUrl: expandedUrl,
                                parentNode: stack[stack.length - 1],
                                urlMap: urlMap
                            }));
                        });
                    } else {
                        firstErrorOrNull = firstErrorOrNull || new Error("Invalid one.getStaticUrl syntax: " + uglify.uglify.gen_code(node));
                    }
                } else if (node[0] === 'stat' && node[1][0] === 'call' && node[1][1][0] === 'dot' &&
                           node[1][1][1][0] === 'name' && node[1][1][1][1] === 'Ext') {
                    var methodName = node[1][1][2];
                    if (methodName === 'setPath') {
                        // TODO:
                        //
                        // Ext.setPath('Foo', 'path/relative/to/the/html/doc');
                    } else if (methodName === 'create') {
                        // TODO:
                        //
                        // Ext.create('Foo.bar.Quux'); // <-- implicit Ext.require
                    } else if (methodName === 'define') {
                        // Ext.define(className, {
                        //     extends: 'Foo.bar.Quux', // <-- implicit Ext.require
                        //     requires: ['Foo.bar.Blah'], // <-- implicit Ext.require
                        //     mixins: {
                        //         theName: 'Foo.Baz' // <-- implicit Ext.require
                        //     }
                        // })

                        var args = node[1][2];
                        if (args.length < 2 || args[0][0] !== 'string' || args[1][0] !== 'object') {
                            // Skip unsupported Ext.define syntax, must be Ext.define(<string>, <object>)
                        } else {
                            args[1][1].forEach(function (keyValue) {
                                if (/^(?:mixins|requires|extends)$/.test(keyValue[0])) {
                                    extractStringNodes(keyValue[1], 'Invalid Ext.define.' + keyValue[0] + ' syntax').forEach(function (stringNode) {
                                        originalRelations.push(new relations.JavaScriptExtJS4Include({
                                            from: that,
                                            to: stringNode[1].replace('.', ':').replace(/\./g, '/') + '.js', // Replace first . with : and the rest with /
                                            node: stringNode
                                        }));
                                    });
                                }
                            });
                        }
                    } else if (methodName === 'exclude') {
                        firstErrorOrNull = firstErrorOrNull || new Error("Ext.exclude not supported");
                    } else if (methodName === 'require' || methodName === 'syncRequire') {
                        var args = node[1][2];
                        if (args.length === 0) {
                            firstErrorOrNull = firstErrorOrNull || new Error('Invalid Ext.require syntax: Must have at least one argument');
                        } else {
                            if (args[0][0] !== 'name') { // The Ext bootstrapper itself contains some Ext.syncRequire(h) statements
                                extractStringNodes(args[0], 'Invalid Ext.require syntax').forEach(function (stringNode) {
                                    originalRelations.push(new relations.JavaScriptExtJS4Include({
                                        from: that,
                                        to: stringNode[1].replace('.', ':').replace(/\./g, '/') + '.js', // Replace first . with : and the rest with /
                                        node: stringNode
                                    }));
                                });
                            }
                        }
                    }
                }

                for (var i = 0 ; i < node.length ; i++) {
                    if (Array.isArray(node[i])) {
                        stack.push(node);
                        traverse(node[i]);
                        stack.pop();
                    }
                }
            }
            traverse(parseTree);
            if (firstErrorOrNull) {
                firstErrorOrNull.message = that.toString() + ': ' + firstErrorOrNull.message;
                cb(firstErrorOrNull);
            } else {
                cb(null, originalRelations);
            }
        }));
    }),

    attachRelation: function (relation, position, adjacentRelation) {
        position = position || 'after';
        relation.from = this;
        if (adjacentRelation) {
            relation.parentNode = adjacentRelation.parentNode;
        } else if (relation.type === 'JavaScriptOneInclude' && (position === 'first' || position === 'last')) {
            relation.parentNode = this.parseTree[1];
        }
        if (relation.type === 'JavaScriptOneGetStaticUrl') {
            if (!adjacentRelation) {
                throw new Error("Cannot attach a JavaScriptOneGetStaticUrl relation without an adjacent relation");
            }
            relation.urlMap = adjacentRelation.urlMap;
            relation.originalUrl = urlTools.inferRelativeUrl(relation.urlMap.originalUrl, relation.to.url);
            relation.urlMap.addExpandedUrl(relation.originalUrl);
        } else {
            relation.node = relation.createNode(this.parseTree);
            if (position === 'before' || position === 'after') {
                var i = relation.parentNode.indexOf(adjacentRelation.node) + (position === 'after' ? 1 : 0);
                relation.parentNode.splice(i, 0, relation.node);
            } else if (position === 'first') {
                relation.parentNode.unshift(relation.node);
            } else if (position === 'last') {
                relation.parentNode.push(relation.node);
            } else {
                throw new Error("assets.JavaScript.attachRelation: Unsupported 'position' value: " + position);
            }
        }
    },

    detachRelation: function (relation) {
        if (relation.type === 'JavaScriptOneGetStaticUrl') {
            if (relation.originalUrl) {
                relation.urlMap.removeExpandedUrl(relation.originalUrl);
            }
        } else if (relation.type !== 'JavaScriptExtJS4Include') {
            relation.parentNode.splice(relation.parentNode.indexOf(relation.node), 1);
            delete relation.node;
            delete relation.parentNode;
        }
    }
});

JavaScript.mergeParseTrees = function (parseTrees, cb) {
    return [
        'toplevel',
        Array.prototype.concat.apply([], parseTrees.map(function (parseTree) {
            return parseTree[1];
        }))
    ];
};

module.exports = JavaScript;
<commit_msg>Reorganized assets.JavaScript.getOriginalRelations.<commit_after>var util = require('util'),
    _ = require('underscore'),
    uglify = require('uglify-js'),
    passError = require('../util/passError'),
    memoizeAsyncAccessor = require('../util/memoizeAsyncAccessor'),
    relations = require('../relations'),
    Text = require('./Text'),
    deepCopy = require('../util/deepCopy'),
    urlTools = require('../util/urlTools');

function JavaScript(config) {
    Text.call(this, config);
}

util.inherits(JavaScript, Text);

_.extend(JavaScript.prototype, {
    contentType: 'application/javascript', // TODO: Double check that this is everyone's recommended value

    defaultExtension: '.js',

    isPretty: false,

    getParseTree: memoizeAsyncAccessor('parseTree', function (cb) {
        var that = this;
        this.getDecodedSrc(passError(cb, function (decodedSrc) {
            var parseTree;
            try {
                parseTree = uglify.parser.parse(decodedSrc);
            } catch (e) {
                return cb(new Error("Parse error in " + (that.url || "inline script") + "\n" +
                                    e.message + " (line " + e.line + ", col " + e.col + ")"));
            }
            cb(null, parseTree);
        }));
    }),

    isEmpty: function (cb) {
        this.getParseTree(passError(cb, function (parseTree) {
            cb(null, parseTree[1].length === 0);
        }));
    },

    minify: function (cb) {
        this.isPretty = false;
        process.nextTick(cb);
    },

    prettyPrint: function (cb) {
        this.isPretty = true;
        process.nextTick(cb);
    },

    getText: function (cb) {
        var that = this;
        that.getParseTree(passError(cb, function (parseTree) {
            cb(null, uglify.uglify.gen_code(parseTree, {beautify: that.isPretty}));
        }));
    },

    getOriginalRelations: memoizeAsyncAccessor('originalRelations', function (cb) {
        var that = this;
        this.getParseTree(passError(cb, function (parseTree) {
            var stack = [],
                originalRelations = [],
                errors = [];

            function extractStringNodes(arrayOrStringOrObjectAst, errorMessage) {
                var stringNodes = [];

                if (arrayOrStringOrObjectAst[0] === 'string') {
                    stringNodes = [arrayOrStringOrObjectAst];
                } else if (arrayOrStringOrObjectAst[0] === 'array' && arrayOrStringOrObjectAst[1].every(function (node) {return node[0] === 'string';})) {
                    stringNodes = arrayOrStringOrObjectAst[1];
                } else if (arrayOrStringOrObjectAst[0] === 'object' && arrayOrStringOrObjectAst[1].every(function (keyValue) {return keyValue[1][0] === 'string';})) {
                    stringNodes = arrayOrStringOrObjectAst[1].map(function (keyValue) {
                        return keyValue[1];
                    });
                } else {
                    errors.push(new Error(errorMessage + ': first argument must be string or array of strings: ' + JSON.stringify(arrayOrStringOrObjectAst)));
                }
                return stringNodes;
            }

            function traverse(node) {
                if (node[0] === 'call' && node[1][0] === 'dot' && node[1][1][0] === 'name' && node[1][1][1] === 'one') {
                    // one.<something>()
                    if (node[1][2] === 'include') {
                        if (node[2].length === 1 && node[2][0][0] === 'string' && stack[stack.length - 1][0] === 'stat') {
                            originalRelations.push(new relations.JavaScriptOneInclude({
                                from: that,
                                to: node[2][0][1],
                                node: stack[stack.length - 1],
                                parentNode: stack[stack.length - 2]
                            }));
                        } else {
                            errors.push(new Error("Invalid one.include syntax: Must be statement-level and takes a single string argument:" + uglify.uglify.gen_code(node)));
                        }
                    } else if (node[1][2] === 'getStaticUrl') {
                        if (node.length >= 3 && node[2][0][0] === 'string') {
                            originalRelations.push(new relations.JavaScriptOneGetStaticUrl({
                                from: that,
                                to: node[2][0][1],
                                urlMap: new relations.JavaScriptOneGetStaticUrl.UrlMap({
                                    node: node,
                                    parentNode: stack[stack.length - 1],
                                    wildCardValueASTs: node[2].slice(1),
                                    originalUrl: node[2][0][1]
                                })
                            }));
                        } else if (node.length === 3 && node[2][0][0] === 'sub') {
                            // Result of JavaScriptOneGetStaticUrl.UrlMap.toExpressionAST
                            var urlMap = relations.JavaScriptOneGetStaticUrl.UrlMap.fromExpressionAST(node[2][0]);
                            urlMap.node = node;
                            urlMap.expandedUrls.forEach(function (expandedUrl) {
                                var mappedUrl = urlMap.expandedUrlMapping[expandedUrl] || expandedUrl;
                                originalRelations.push(new relations.JavaScriptOneGetStaticUrl({
                                    from: that,
                                    to: mappedUrl,
                                    originalUrl: expandedUrl,
                                    node: node,
                                    parentNode: stack[stack.length - 1],
                                    urlMap: urlMap
                                }));
                            });
                        } else {
                            errors.push(new Error("Invalid one.getStaticUrl syntax: " + uglify.uglify.gen_code(node)));
                        }
                    }
                } else if (node[0] === 'stat' && node[1][0] === 'call' && node[1][1][0] === 'dot' &&
                           node[1][1][1][0] === 'name' && node[1][1][1][1] === 'Ext') {
                    var methodName = node[1][1][2];
                    if (methodName === 'setPath') {
                        // TODO:
                        //
                        // Ext.setPath('Foo', 'path/relative/to/the/html/doc');
                    } else if (methodName === 'create') {
                        // TODO:
                        //
                        // Ext.create('Foo.bar.Quux'); // <-- implicit Ext.require
                    } else if (methodName === 'define') {
                        // Ext.define(className, {
                        //     extends: 'Foo.bar.Quux', // <-- implicit Ext.require
                        //     requires: ['Foo.bar.Blah'], // <-- implicit Ext.require
                        //     mixins: {
                        //         theName: 'Foo.Baz' // <-- implicit Ext.require
                        //     }
                        // })

                        var args = node[1][2];
                        if (args.length < 2 || args[0][0] !== 'string' || args[1][0] !== 'object') {
                            // Skip unsupported Ext.define syntax, must be Ext.define(<string>, <object>)
                        } else {
                            args[1][1].forEach(function (keyValue) {
                                if (/^(?:mixins|requires|extends)$/.test(keyValue[0])) {
                                    extractStringNodes(keyValue[1], 'Invalid Ext.define.' + keyValue[0] + ' syntax').forEach(function (stringNode) {
                                        originalRelations.push(new relations.JavaScriptExtJS4Include({
                                            from: that,
                                            to: stringNode[1].replace('.', ':').replace(/\./g, '/') + '.js', // Replace first . with : and the rest with /
                                            node: stringNode
                                        }));
                                    });
                                }
                            });
                        }
                    } else if (methodName === 'exclude') {
                        errors.push(new Error("Ext.exclude not supported"));
                    } else if (methodName === 'require' || methodName === 'syncRequire') {
                        var args = node[1][2];
                        if (args.length === 0) {
                            errors.push(new Error('Invalid Ext.require syntax: Must have at least one argument'));
                        } else {
                            if (args[0][0] !== 'name') { // The Ext bootstrapper itself contains some Ext.syncRequire(h) statements
                                extractStringNodes(args[0], 'Invalid Ext.require syntax').forEach(function (stringNode) {
                                    originalRelations.push(new relations.JavaScriptExtJS4Include({
                                        from: that,
                                        to: stringNode[1].replace('.', ':').replace(/\./g, '/') + '.js', // Replace first . with : and the rest with /
                                        node: stringNode
                                    }));
                                });
                            }
                        }
                    }
                }

                for (var i = 0 ; i < node.length ; i++) {
                    if (Array.isArray(node[i])) {
                        stack.push(node);
                        traverse(node[i]);
                        stack.pop();
                    }
                }
            }
            traverse(parseTree);
            if (errors.length) {
                cb(new Error(_.pluck(errors, 'message').join("\n")));
            } else {
                cb(null, originalRelations);
            }
        }));
    }),

    attachRelation: function (relation, position, adjacentRelation) {
        position = position || 'after';
        relation.from = this;
        if (adjacentRelation) {
            relation.parentNode = adjacentRelation.parentNode;
        } else if (relation.type === 'JavaScriptOneInclude' && (position === 'first' || position === 'last')) {
            relation.parentNode = this.parseTree[1];
        }
        if (relation.type === 'JavaScriptOneGetStaticUrl') {
            if (!adjacentRelation) {
                throw new Error("Cannot attach a JavaScriptOneGetStaticUrl relation without an adjacent relation");
            }
            relation.urlMap = adjacentRelation.urlMap;
            relation.originalUrl = urlTools.inferRelativeUrl(relation.urlMap.originalUrl, relation.to.url);
            relation.urlMap.addExpandedUrl(relation.originalUrl);
        } else {
            relation.node = relation.createNode(this.parseTree);
            if (position === 'before' || position === 'after') {
                var i = relation.parentNode.indexOf(adjacentRelation.node) + (position === 'after' ? 1 : 0);
                relation.parentNode.splice(i, 0, relation.node);
            } else if (position === 'first') {
                relation.parentNode.unshift(relation.node);
            } else if (position === 'last') {
                relation.parentNode.push(relation.node);
            } else {
                throw new Error("assets.JavaScript.attachRelation: Unsupported 'position' value: " + position);
            }
        }
    },

    detachRelation: function (relation) {
        if (relation.type === 'JavaScriptOneGetStaticUrl') {
            if (relation.originalUrl) {
                relation.urlMap.removeExpandedUrl(relation.originalUrl);
            }
        } else if (relation.type !== 'JavaScriptExtJS4Include') {
            relation.parentNode.splice(relation.parentNode.indexOf(relation.node), 1);
            delete relation.node;
            delete relation.parentNode;
        }
    }
});

JavaScript.mergeParseTrees = function (parseTrees, cb) {
    return [
        'toplevel',
        Array.prototype.concat.apply([], parseTrees.map(function (parseTree) {
            return parseTree[1];
        }))
    ];
};

module.exports = JavaScript;
<|endoftext|>


<commit_before>var https = require('https');
var querystring = require('querystring');
var utils = require('./utils.js');

var rejectUnauthorized = false;

function AtmoClient(atmoLocation, proxy) {
    //TODO: proper handling of atmo URL, https:// etc...
    this.atmoLocation = atmoLocation;
    this.atmoPath = '/api/v1';
    this.basedProxy = new Buffer(proxy).toString('base64');
    this.proxy = new Buffer(proxy).toString();
}

AtmoClient.prototype.getPortMappings = function (cb) {
    request = https.request({
        hostname: this.atmoLocation,
        path: this.atmoPath + '/port_mappings/',
        method: 'GET',
        rejectUnauthorized: rejectUnauthorized,
        ca: utils.getCAs(),
        cert: this.proxy,
        key: this.proxy,
        headers: {
            'PROXY': this.basedProxy
        }
    }, function (res) {
        //console.log(res.statusCode);
        if (res.statusCode != 200) {
            cb(new Error('error getting port mappings: ' + res.statusCode + ', ' + res.statusMessage));
            //console.log(res);
            return;
        }
        res.setEncoding('utf8');
        var data = '';
        res.on('data', function (chunk) {
            data += chunk;
        });
        res.on('end', function () {
            //console.log('end of response', data);
            var resData = JSON.parse(data);
            cb(null, resData.port_mappings);
        });
    });

    request.on('error', function (e) {
        console.log('Problem with getting port mappings:', e);
        cb(e);
    });

    request.end();
};

AtmoClient.prototype.getPortMappingTemplate = function (portMappingTemplateId, cb) {
    request = https.request({
        hostname: this.atmoLocation,
        path: this.atmoPath + '/port_mapping_templates/' + portMappingTemplateId,
        method: 'GET',
        rejectUnauthorized: rejectUnauthorized,
        ca: utils.getCAs(),
        cert: this.proxy,
        key: this.proxy,
        headers: {
            'PROXY': this.basedProxy
        }
    }, function (res) {
        //console.log(res.statusCode);
        if (res.statusCode != 200) {
            cb(new Error('error getting port mapping template: ' + res.statusCode + ', ' + res.statusMessage));
            //console.log(res);
            return;
        }
        res.setEncoding('utf8');
        var data = '';
        res.on('data', function (chunk) {
            data += chunk;
        });
        res.on('end', function () {
            //console.log('end of response', data);
            var resData = JSON.parse(data);
            cb(null, resData.port_mapping_template);
        });
    });

    request.on('error', function (e) {
        console.log('Problem with getting port mapping template:', e);
        cb(e);
    });

    request.end();
};

AtmoClient.prototype.getVirtualMachine = function (id, cb) {
    request = https.request({
        hostname: this.atmoLocation,
        path: this.atmoPath + '/virtual_machines/' + id,
        method: 'GET',
        rejectUnauthorized: rejectUnauthorized,
        ca: utils.getCAs(),
        cert: this.proxy,
        key: this.proxy,
        headers: {
            'PROXY': this.basedProxy
        }
    }, function (res) {
        //console.log(res.statusCode);
        if (res.statusCode != 200) {
            cb(new Error('error getting vm: ' + res.statusCode + ', ' + res.statusMessage));
            //console.log(res);
            return;
        }
        res.setEncoding('utf8');
        var data = '';
        res.on('data', function (chunk) {
            data += chunk;
        });
        res.on('end', function () {
            //console.log('end of response', data);
            var resData = JSON.parse(data);
            cb(null, resData.virtual_machine);
        });
    });

    request.on('error', function (e) {
        console.log('Problem with getting vm:', e);
        cb(e);
    });

    request.end();
};

AtmoClient.prototype.newAppliance = function (appliance, cb) {
    var data = {
        appliance: {
            appliance_set_id: appliance.setId,
            name: appliance.name,
            configuration_template_id: appliance.templateId,
            params: appliance.params ? appliance.params : []
        }
    };

    var postData = JSON.stringify(data);

    //console.log(postData);

    request = https.request({
        hostname: this.atmoLocation,
        path: this.atmoPath + '/appliances',
        method: 'POST',
        rejectUnauthorized: rejectUnauthorized,
        ca: utils.getCAs(),
        cert: this.proxy,
        key: this.proxy,
        headers: {
            'Content-Type': 'application/json',
            'Content-Length': postData.length,
            'PROXY': this.basedProxy
        }
    }, function (res) {
        //console.log(res.statusCode);
        if (res.statusCode != 201) {
            //console.log(res);
            cb(new Error('error creating appliance: ' + res.statusCode + ', ' + res.statusMessage));
            return;
        }
        res.setEncoding('utf8');
        var data = '';
        res.on('data', function (chunk) {
            data += chunk;
        });
        res.on('end', function () {
            //console.log('end of response', data);
            var resData = JSON.parse(data);
            cb(null, resData.appliance);
        });
    });

    request.on('error', function (e) {
        console.log('Problem with creating appliance:', e);
        cb(e);
    });

    request.write(postData);
    request.end();
};

AtmoClient.prototype.newApplianceSet = function (name, appliances, cb) {
    var data = {
        appliance_set: {
            name: name,
            //optimization_policy: 'default',
            appliances: []
        }
    };

    if (appliances) {
        appliances.forEach(function (appliance) {
            //data.appliances.push(
            data.appliance_set.appliances.push(
                {
                    configuration_template_id: appliance.applianceId,
                    params: appliance.params,
                    vms: appliance.vms
                }
            )
        });
    }

    var postData = JSON.stringify(data);

    //console.log(postData);

    var request = https.request({
        hostname: this.atmoLocation,
        path: this.atmoPath + '/appliance_sets',
        method: 'POST',
        rejectUnauthorized: rejectUnauthorized,
        ca: utils.getCAs(),
        cert: this.proxy,
        key: this.proxy,
        headers: {
            'Content-Type': 'application/json',
            'Content-Length': postData.length,
            'PROXY': this.basedProxy
        }
    }, function (res) {
        //console.log(res.statusCode);
        if (res.statusCode != 201) {
            cb(new Error('error creating appliance set: ' + res.statusCode + ', ' + res.statusMessage));
            //console.log(res);
            return;
        }
        res.setEncoding('utf8');
        var data = '';
        res.on('data', function (chunk) {
            data += chunk;
        });
        res.on('end', function () {
            //console.log('end of response', data);
            var resData = JSON.parse(data);
            cb(null, resData.appliance_set);
        });
    });

    request.on('error', function (e) {
        console.log('Problem with creating appliance set:', e);
        cb(e);
    });

    request.write(postData);
    request.end();
};

AtmoClient.prototype.getApplianceSets = function (cb) {
    var request = https.request({
        hostname: this.atmoLocation,
        path: this.atmoPath + '/appliance_sets',
        method: 'GET',
        rejectUnauthorized: rejectUnauthorized,
        ca: utils.getCAs(),
        cert: this.proxy,
        key: this.proxy,
        headers: {
            'PROXY': this.basedProxy
        }
    }, function (res) {
        //console.log(res.statusCode);
        if (res.statusCode != 200) {
            cb(new Error('error getting appliance sets: ' + res.statusCode + ', ' + res.statusMessage));
            //console.log(res);
            return;
        }
        res.setEncoding('utf8');
        var data = '';
        res.on('data', function (chunk) {
            data += chunk;
        });
        res.on('end', function () {
            //console.log('end of response', data);
            var resData = JSON.parse(data);
            cb(null, resData.appliance_sets);
        });
    });

    request.on('error', function (e) {
        console.log('Problem with getting appliance sets:', e);
        cb(e);
    });

    request.end();
};

AtmoClient.prototype.deleteApplianceSet = function (applianceSetId, cb) {
    var request = https.request({
        hostname: this.atmoLocation,
        path: this.atmoPath + '/appliance_sets/' + applianceSetId,
        method: 'DELETE',
        rejectUnauthorized: rejectUnauthorized,
        ca: utils.getCAs(),
        cert: this.proxy,
        key: this.proxy,
        headers: {
            'PROXY': this.basedProxy
        }
    }, function (res) {
        //console.log(res.statusCode);
        if (res.statusCode != 200) {
            cb(new Error('error deleting appliance sets: ' + res.statusCode + ', ' + res.statusMessage));
            //console.log(res);
            return;
        }
        cb(null);
    });

    request.on('error', function (e) {
        console.log('Problem with deleting appliance sets:', e);
        cb(e);
    });

    request.end();
};

function createClient(atmoLocation, basedProxy) {
    return new AtmoClient(atmoLocation, basedProxy);
}

module.exports.createClient = createClient;<commit_msg>Added getAppliance.<commit_after>var https = require('https');
var querystring = require('querystring');
var utils = require('./utils.js');

var rejectUnauthorized = false;

function AtmoClient(atmoLocation, proxy) {
    //TODO: proper handling of atmo URL, https:// etc...
    this.atmoLocation = atmoLocation;
    this.atmoPath = '/api/v1';
    this.basedProxy = new Buffer(proxy).toString('base64');
    this.proxy = new Buffer(proxy).toString();
}

AtmoClient.prototype.getPortMappings = function (cb) {
    request = https.request({
        hostname: this.atmoLocation,
        path: this.atmoPath + '/port_mappings/',
        method: 'GET',
        rejectUnauthorized: rejectUnauthorized,
        ca: utils.getCAs(),
        cert: this.proxy,
        key: this.proxy,
        headers: {
            'PROXY': this.basedProxy
        }
    }, function (res) {
        //console.log(res.statusCode);
        if (res.statusCode != 200) {
            cb(new Error('error getting port mappings: ' + res.statusCode + ', ' + res.statusMessage));
            //console.log(res);
            return;
        }
        res.setEncoding('utf8');
        var data = '';
        res.on('data', function (chunk) {
            data += chunk;
        });
        res.on('end', function () {
            //console.log('end of response', data);
            var resData = JSON.parse(data);
            cb(null, resData.port_mappings);
        });
    });

    request.on('error', function (e) {
        console.log('Problem with getting port mappings:', e);
        cb(e);
    });

    request.end();
};

AtmoClient.prototype.getPortMappingTemplate = function (portMappingTemplateId, cb) {
    request = https.request({
        hostname: this.atmoLocation,
        path: this.atmoPath + '/port_mapping_templates/' + portMappingTemplateId,
        method: 'GET',
        rejectUnauthorized: rejectUnauthorized,
        ca: utils.getCAs(),
        cert: this.proxy,
        key: this.proxy,
        headers: {
            'PROXY': this.basedProxy
        }
    }, function (res) {
        //console.log(res.statusCode);
        if (res.statusCode != 200) {
            cb(new Error('error getting port mapping template: ' + res.statusCode + ', ' + res.statusMessage));
            //console.log(res);
            return;
        }
        res.setEncoding('utf8');
        var data = '';
        res.on('data', function (chunk) {
            data += chunk;
        });
        res.on('end', function () {
            //console.log('end of response', data);
            var resData = JSON.parse(data);
            cb(null, resData.port_mapping_template);
        });
    });

    request.on('error', function (e) {
        console.log('Problem with getting port mapping template:', e);
        cb(e);
    });

    request.end();
};

AtmoClient.prototype.getVirtualMachine = function (id, cb) {
    request = https.request({
        hostname: this.atmoLocation,
        path: this.atmoPath + '/virtual_machines/' + id,
        method: 'GET',
        rejectUnauthorized: rejectUnauthorized,
        ca: utils.getCAs(),
        cert: this.proxy,
        key: this.proxy,
        headers: {
            'PROXY': this.basedProxy
        }
    }, function (res) {
        //console.log(res.statusCode);
        if (res.statusCode != 200) {
            cb(new Error('error getting vm: ' + res.statusCode + ', ' + res.statusMessage));
            //console.log(res);
            return;
        }
        res.setEncoding('utf8');
        var data = '';
        res.on('data', function (chunk) {
            data += chunk;
        });
        res.on('end', function () {
            //console.log('end of response', data);
            var resData = JSON.parse(data);
            cb(null, resData.virtual_machine);
        });
    });

    request.on('error', function (e) {
        console.log('Problem with getting vm:', e);
        cb(e);
    });

    request.end();
};

AtmoClient.prototype.getAppliance = function (id, cb) {
    request = https.request({
        hostname: this.atmoLocation,
        path: this.atmoPath + '/appliances/' + id,
        method: 'GET',
        rejectUnauthorized: rejectUnauthorized,
        ca: utils.getCAs(),
        cert: this.proxy,
        key: this.proxy,
        headers: {
            'PROXY': this.basedProxy
        }
    }, function (res) {
        //console.log(res.statusCode);
        if (res.statusCode != 200) {
            cb(new Error('error getting appliance: ' + res.statusCode + ', ' + res.statusMessage));
            //console.log(res);
            return;
        }
        res.setEncoding('utf8');
        var data = '';
        res.on('data', function (chunk) {
            data += chunk;
        });
        res.on('end', function () {
            //console.log('end of response', data);
            var resData = JSON.parse(data);
            cb(null, resData.virtual_machine);
        });
    });

    request.on('error', function (e) {
        console.log('Problem with getting appliance:', e);
        cb(e);
    });

    request.end();
};

AtmoClient.prototype.newAppliance = function (appliance, cb) {
    var data = {
        appliance: {
            appliance_set_id: appliance.setId,
            name: appliance.name,
            configuration_template_id: appliance.templateId,
            params: appliance.params ? appliance.params : []
        }
    };

    var postData = JSON.stringify(data);

    //console.log(postData);

    request = https.request({
        hostname: this.atmoLocation,
        path: this.atmoPath + '/appliances',
        method: 'POST',
        rejectUnauthorized: rejectUnauthorized,
        ca: utils.getCAs(),
        cert: this.proxy,
        key: this.proxy,
        headers: {
            'Content-Type': 'application/json',
            'Content-Length': postData.length,
            'PROXY': this.basedProxy
        }
    }, function (res) {
        //console.log(res.statusCode);
        if (res.statusCode != 201) {
            //console.log(res);
            cb(new Error('error creating appliance: ' + res.statusCode + ', ' + res.statusMessage));
            return;
        }
        res.setEncoding('utf8');
        var data = '';
        res.on('data', function (chunk) {
            data += chunk;
        });
        res.on('end', function () {
            //console.log('end of response', data);
            var resData = JSON.parse(data);
            cb(null, resData.appliance);
        });
    });

    request.on('error', function (e) {
        console.log('Problem with creating appliance:', e);
        cb(e);
    });

    request.write(postData);
    request.end();
};

AtmoClient.prototype.newApplianceSet = function (name, appliances, cb) {
    var data = {
        appliance_set: {
            name: name,
            //optimization_policy: 'default',
            appliances: []
        }
    };

    if (appliances) {
        appliances.forEach(function (appliance) {
            //data.appliances.push(
            data.appliance_set.appliances.push(
                {
                    configuration_template_id: appliance.applianceId,
                    params: appliance.params,
                    vms: appliance.vms
                }
            )
        });
    }

    var postData = JSON.stringify(data);

    //console.log(postData);

    var request = https.request({
        hostname: this.atmoLocation,
        path: this.atmoPath + '/appliance_sets',
        method: 'POST',
        rejectUnauthorized: rejectUnauthorized,
        ca: utils.getCAs(),
        cert: this.proxy,
        key: this.proxy,
        headers: {
            'Content-Type': 'application/json',
            'Content-Length': postData.length,
            'PROXY': this.basedProxy
        }
    }, function (res) {
        //console.log(res.statusCode);
        if (res.statusCode != 201) {
            cb(new Error('error creating appliance set: ' + res.statusCode + ', ' + res.statusMessage));
            //console.log(res);
            return;
        }
        res.setEncoding('utf8');
        var data = '';
        res.on('data', function (chunk) {
            data += chunk;
        });
        res.on('end', function () {
            //console.log('end of response', data);
            var resData = JSON.parse(data);
            cb(null, resData.appliance_set);
        });
    });

    request.on('error', function (e) {
        console.log('Problem with creating appliance set:', e);
        cb(e);
    });

    request.write(postData);
    request.end();
};

AtmoClient.prototype.getApplianceSets = function (cb) {
    var request = https.request({
        hostname: this.atmoLocation,
        path: this.atmoPath + '/appliance_sets',
        method: 'GET',
        rejectUnauthorized: rejectUnauthorized,
        ca: utils.getCAs(),
        cert: this.proxy,
        key: this.proxy,
        headers: {
            'PROXY': this.basedProxy
        }
    }, function (res) {
        //console.log(res.statusCode);
        if (res.statusCode != 200) {
            cb(new Error('error getting appliance sets: ' + res.statusCode + ', ' + res.statusMessage));
            //console.log(res);
            return;
        }
        res.setEncoding('utf8');
        var data = '';
        res.on('data', function (chunk) {
            data += chunk;
        });
        res.on('end', function () {
            //console.log('end of response', data);
            var resData = JSON.parse(data);
            cb(null, resData.appliance_sets);
        });
    });

    request.on('error', function (e) {
        console.log('Problem with getting appliance sets:', e);
        cb(e);
    });

    request.end();
};

AtmoClient.prototype.deleteApplianceSet = function (applianceSetId, cb) {
    var request = https.request({
        hostname: this.atmoLocation,
        path: this.atmoPath + '/appliance_sets/' + applianceSetId,
        method: 'DELETE',
        rejectUnauthorized: rejectUnauthorized,
        ca: utils.getCAs(),
        cert: this.proxy,
        key: this.proxy,
        headers: {
            'PROXY': this.basedProxy
        }
    }, function (res) {
        //console.log(res.statusCode);
        if (res.statusCode != 200) {
            cb(new Error('error deleting appliance sets: ' + res.statusCode + ', ' + res.statusMessage));
            //console.log(res);
            return;
        }
        cb(null);
    });

    request.on('error', function (e) {
        console.log('Problem with deleting appliance sets:', e);
        cb(e);
    });

    request.end();
};

function createClient(atmoLocation, basedProxy) {
    return new AtmoClient(atmoLocation, basedProxy);
}

module.exports.createClient = createClient;<|endoftext|>


<commit_before>'use babel';

import { CompositeDisposable, File } from 'atom';

export default {
  subscriptions: null,

  activate() {
    // Events subscribed to in atom's system can be easily cleaned up with a CompositeDisposable
    this.subscriptions = new CompositeDisposable();

    this.subscriptions.add(atom.commands.add('atom-workspace', {
      'atom-jump-to-spec:open-spec': () => this.openSpec(),
    }));
  },

  deactivate() {
    this.subscriptions.dispose();
  },

  serialize() {
    return {};
  },

  openSpec() {
    const editor = atom.workspace.getActiveTextEditor();
    if (editor) {
      this.getSpecFilePath(editor);
    }
  },

  getSpecFilePath(editor) {
    const srcPath = atom.project.relativizePath(editor.getPath());
    ['/test/unit', '/spec', '/test', '/src'].forEach(testDir => {
      ['.spec', '-spec'].forEach(testPostfix => {
        let specPath = srcPath[0] + testDir + srcPath[1].slice(3);
        const indexOfExtension = specPath.lastIndexOf('.');
        specPath = specPath.slice(0, indexOfExtension) + testPostfix + specPath.slice(indexOfExtension);
        const testFile = new File(specPath);
        testFile.exists().then(doesExist => {
          if (doesExist) {
            atom.workspace.open(specPath);
          }
        });
      });
    });
  },
};
<commit_msg>Add another test file location<commit_after>'use babel';

import { CompositeDisposable, File } from 'atom';

export default {
  subscriptions: null,

  activate() {
    // Events subscribed to in atom's system can be easily cleaned up with a CompositeDisposable
    this.subscriptions = new CompositeDisposable();

    this.subscriptions.add(atom.commands.add('atom-workspace', {
      'atom-jump-to-spec:open-spec': () => this.openSpec(),
    }));
  },

  deactivate() {
    this.subscriptions.dispose();
  },

  serialize() {
    return {};
  },

  openSpec() {
    const editor = atom.workspace.getActiveTextEditor();
    if (editor) {
      this.getSpecFilePath(editor);
    }
  },

  getSpecFilePath(editor) {
    const srcPath = atom.project.relativizePath(editor.getPath());
    ['/test/unit', '/test/unit/spec', '/spec', '/test', '/src'].forEach(testDir => {
      ['.spec', '-spec'].forEach(testPostfix => {
        let specPath = srcPath[0] + testDir + srcPath[1].slice(3);
        const indexOfExtension = specPath.lastIndexOf('.');
        specPath = specPath.slice(0, indexOfExtension) + testPostfix + specPath.slice(indexOfExtension);
        const testFile = new File(specPath);
        testFile.exists().then(doesExist => {
          if (doesExist) {
            atom.workspace.open(specPath);
          }
        });
      });
    });
  },
};
<|endoftext|>


<commit_before>import Component from 'flarum/Component';
import Checkbox from 'flarum/components/Checkbox';
import icon from 'flarum/helpers/icon';
import ItemList from 'flarum/utils/ItemList';

/**
 * The `NotificationGrid` component displays a table of notification types and
 * methods, allowing the user to toggle each combination.
 *
 * ### Props
 *
 * - `user`
 */
export default class NotificationGrid extends Component {
  init() {
    /**
     * Information about the available notification methods.
     *
     * @type {Array}
     */
    this.methods = [
      {name: 'alert', icon: 'bell', label: app.translator.trans('core.forum.settings.notify_by_web_heading')},
      {name: 'email', icon: 'envelope-o', label: app.translator.trans('core.forum.settings.notify_by_email_heading')}
    ];

    /**
     * A map of notification type-method combinations to the checkbox instances
     * that represent them.
     *
     * @type {Object}
     */
    this.inputs = {};

    /**
     * Information about the available notification types.
     *
     * @type {Object}
     */
    this.types = this.notificationTypes().toArray();

    // For each of the notification type-method combinations, create and store a
    // new checkbox component instance, which we will render in the view.
    this.types.forEach(type => {
      this.methods.forEach(method => {
        const key = this.preferenceKey(type.name, method.name);
        const preference = this.props.user.preferences()[key];

        this.inputs[key] = new Checkbox({
          state: !!preference,
          disabled: typeof preference === 'undefined',
          onchange: () => this.toggle([key])
        });
      });
    });
  }

  view() {
    return (

            {this.methods.map(method => (

                {icon(method.icon)} {method.label}

            ))}

          {this.types.map(type => (

                {icon(type.icon)} {type.label}

              {this.methods.map(method => (

                  {this.inputs[this.preferenceKey(type.name, method.name)].render()}

              ))}

          ))}

    );
  }

  config(isInitialized) {
    if (isInitialized) return;

    this.$('thead .NotificationGrid-groupToggle').bind('mouseenter mouseleave', function(e) {
      const i = parseInt($(this).index(), 10) + 1;
      $(this).parents('table').find('td:nth-child(' + i + ')').toggleClass('highlighted', e.type === 'mouseenter');
    });

    this.$('tbody .NotificationGrid-groupToggle').bind('mouseenter mouseleave', function(e) {
      $(this).parent().find('td').toggleClass('highlighted', e.type === 'mouseenter');
    });
  }

  /**
   * Toggle the state of the given preferences, based on the value of the first
   * one.
   *
   * @param {Array} keys
   */
  toggle(keys) {
    const user = this.props.user;
    const preferences = user.preferences();
    const enabled = !preferences[keys[0]];

    keys.forEach(key => {
      const control = this.inputs[key];

      control.loading = true;
      preferences[key] = control.props.state = enabled;
    });

    m.redraw();

    user.save({preferences}).then(() => {
      keys.forEach(key => this.inputs[key].loading = false);

      m.redraw();
    });
  }

  /**
   * Toggle all notification types for the given method.
   *
   * @param {String} method
   */
  toggleMethod(method) {
    const keys = this.types
      .map(type => this.preferenceKey(type.name, method))
      .filter(key => !this.inputs[key].props.disabled);

    this.toggle(keys);
  }

  /**
   * Toggle all notification methods for the given type.
   *
   * @param {String} type
   */
  toggleType(type) {
    const keys = this.methods
      .map(method => this.preferenceKey(type, method.name))
      .filter(key => !this.inputs[key].props.disabled);

    this.toggle(keys);
  }

  /**
   * Get the name of the preference key for the given notification type-method
   * combination.
   *
   * @param {String} type
   * @param {String} method
   * @return {String}
   */
  preferenceKey(type, method) {
    return 'notify_' + type + '_' + method;
  }

  /**
   * Build an item list for the notification types to display in the grid.
   *
   * Each notification type is an object which has the following properties:
   *
   * - `name` The name of the notification type.
   * - `label` The label to display in the notification grid row.
   *
   * @return {ItemList}
   */
  notificationTypes() {
    const items = new ItemList();

    items.add('discussionRenamed', {
      name: 'discussionRenamed',
      icon: 'pencil',
      label: app.translator.trans('core.forum.settings.notify_discussion_renamed_label')
    });

    return items;
  }
}
<commit_msg>Use an extendable ItemList for notification methods<commit_after>import Component from 'flarum/Component';
import Checkbox from 'flarum/components/Checkbox';
import icon from 'flarum/helpers/icon';
import ItemList from 'flarum/utils/ItemList';

/**
 * The `NotificationGrid` component displays a table of notification types and
 * methods, allowing the user to toggle each combination.
 *
 * ### Props
 *
 * - `user`
 */
export default class NotificationGrid extends Component {
  init() {
    /**
     * Information about the available notification methods.
     *
     * @type {Array}
     */
    this.methods = this.notificationMethods().toArray();

    /**
     * A map of notification type-method combinations to the checkbox instances
     * that represent them.
     *
     * @type {Object}
     */
    this.inputs = {};

    /**
     * Information about the available notification types.
     *
     * @type {Object}
     */
    this.types = this.notificationTypes().toArray();

    // For each of the notification type-method combinations, create and store a
    // new checkbox component instance, which we will render in the view.
    this.types.forEach(type => {
      this.methods.forEach(method => {
        const key = this.preferenceKey(type.name, method.name);
        const preference = this.props.user.preferences()[key];

        this.inputs[key] = new Checkbox({
          state: !!preference,
          disabled: typeof preference === 'undefined',
          onchange: () => this.toggle([key])
        });
      });
    });
  }

  view() {
    return (

            {this.methods.map(method => (

                {icon(method.icon)} {method.label}

            ))}

          {this.types.map(type => (

                {icon(type.icon)} {type.label}

              {this.methods.map(method => (

                  {this.inputs[this.preferenceKey(type.name, method.name)].render()}

              ))}

          ))}

    );
  }

  config(isInitialized) {
    if (isInitialized) return;

    this.$('thead .NotificationGrid-groupToggle').bind('mouseenter mouseleave', function(e) {
      const i = parseInt($(this).index(), 10) + 1;
      $(this).parents('table').find('td:nth-child(' + i + ')').toggleClass('highlighted', e.type === 'mouseenter');
    });

    this.$('tbody .NotificationGrid-groupToggle').bind('mouseenter mouseleave', function(e) {
      $(this).parent().find('td').toggleClass('highlighted', e.type === 'mouseenter');
    });
  }

  /**
   * Toggle the state of the given preferences, based on the value of the first
   * one.
   *
   * @param {Array} keys
   */
  toggle(keys) {
    const user = this.props.user;
    const preferences = user.preferences();
    const enabled = !preferences[keys[0]];

    keys.forEach(key => {
      const control = this.inputs[key];

      control.loading = true;
      preferences[key] = control.props.state = enabled;
    });

    m.redraw();

    user.save({preferences}).then(() => {
      keys.forEach(key => this.inputs[key].loading = false);

      m.redraw();
    });
  }

  /**
   * Toggle all notification types for the given method.
   *
   * @param {String} method
   */
  toggleMethod(method) {
    const keys = this.types
      .map(type => this.preferenceKey(type.name, method))
      .filter(key => !this.inputs[key].props.disabled);

    this.toggle(keys);
  }

  /**
   * Toggle all notification methods for the given type.
   *
   * @param {String} type
   */
  toggleType(type) {
    const keys = this.methods
      .map(method => this.preferenceKey(type, method.name))
      .filter(key => !this.inputs[key].props.disabled);

    this.toggle(keys);
  }

  /**
   * Get the name of the preference key for the given notification type-method
   * combination.
   *
   * @param {String} type
   * @param {String} method
   * @return {String}
   */
  preferenceKey(type, method) {
    return 'notify_' + type + '_' + method;
  }

  /**
   * Build an item list for the notification methods to display in the grid.
   *
   * Each notification method is an object which has the following properties:
   *
   * - `name` The name of the notification method.
   * - `icon` The icon to display in the column header.
   * - `label` The label to display in the column header.
   *
   * @return {ItemList}
   */
  notificationMethods() {
    const items = new ItemList();

    items.add('alert', {
      name: 'alert',
      icon: 'bell',
      label: app.translator.trans('core.forum.settings.notify_by_web_heading'),
    });

    items.add('email', {
      name: 'email',
      icon: 'envelope-o',
      label: app.translator.trans('core.forum.settings.notify_by_email_heading'),
    });

    return items;
  }

  /**
   * Build an item list for the notification types to display in the grid.
   *
   * Each notification type is an object which has the following properties:
   *
   * - `name` The name of the notification type.
   * - `label` The label to display in the notification grid row.
   *
   * @return {ItemList}
   */
  notificationTypes() {
    const items = new ItemList();

    items.add('discussionRenamed', {
      name: 'discussionRenamed',
      icon: 'pencil',
      label: app.translator.trans('core.forum.settings.notify_discussion_renamed_label')
    });

    return items;
  }
}
<|endoftext|>