<commit_before>var util = require('util'),
    EventEmitter = require('events').EventEmitter,
    logger = require('../logger'),
    _ = require('underscore');

var Debugger = function(debuggerBackend, tiProject) {
    this.backend = debuggerBackend;
    this.threads = {};
    this.scripts = {};
    this.scriptUriToIdMap = {};
    this.breakpoints = {};
    this.logMessages = [];
    this.options = {};
    this.tiProject = tiProject;
    var self = this;
    debuggerBackend.on('message', function(msg) {
        //self.notifyBackendMessage(message);
        //logger.debug("notifyBackendMessage: " + JSON.stringify(msg));
        var method = 'dbg_' + msg.message;
        if (self[method]) {
            self[method].call(self, msg.args);
        }
    });

    this.enumerateScripts();
};

util.inherits(Debugger, EventEmitter);

Debugger.prototype.newScriptId = function() {
    if (!this.lastScriptId) {
        this.lastScriptId = 0;
    }
    this.lastScriptId++;
    return this.lastScriptId;
};

Debugger.prototype.enumerateScripts = function() {
    var self = this;
    this.tiProject.findResourceFilesOfType('.js', function(err, fileName) {

        self.newScript({
            scriptId: self.newScriptId(),
            uri: fileName.replace(self.tiProject.projectFile('Resources'), 'app:'),
            "function": '',
            line: 0,
            linecount: 0
        });
    });
};

Debugger.prototype.dispatchMessage = function(message, data) {
    var msg = {
        message: message,
        data: data
    };
    this.emit('message', msg);
};

Debugger.prototype.dispatchCommand = function(command, args, callback) {
    if (!this.backend) {
        callback();
        return;
    }

    this.backend.sendCommand({
        command: command,
        args: args
    }, callback);
};

Debugger.prototype.newThread = function(thread) {
    this.threads[thread.threadId] = thread;
    this.dispatchMessage('threadAdded', thread);
};

Debugger.prototype.removeThread = function(thread) {
    thread = this.threads[thread.threadId];
    delete this.threads[thread.threadId];
    this.dispatchMessage('threadRemoved', thread);
};

Debugger.prototype.scriptFromUri = function(uri) {
    var scriptId = this.scriptUriToIdMap[uri];
    if (!scriptId) {
        return null;
    }
    return this.scripts[scriptId];
};

Debugger.prototype.newScript = function(script) {
    var s = this.scriptFromUri(script.uri);
    script.scriptId = '' + script.scriptId;
    var scriptId = s ? s.scriptId : script.scriptId; //if the script has already been added through 'enumerateScripts()', use the id generated there
    script.scriptId = scriptId; // overwrite the scriptId, so DevTools doesn't get confused
    this.scripts[scriptId] = script;
    this.scriptUriToIdMap[script.uri] = scriptId;
    this.dispatchMessage('scriptAdded', script);
};

Debugger.prototype.removeScript = function(script) {
    script = this.scripts[script.scriptId];
    delete this.scripts[script.scriptId];
    delete this.scriptUriToIdMap[script.uri];
    this.dispatchMessage('scriptRemoved', script);
};

Debugger.prototype.dbg_threads = function(data) {
    if (data.action == 'created') {
        this.newThread({
            threadId: data.threadId,
            name: data.name
        });
    }
    else if (data.action == 'destroyed') {
        this.removeThread(data.id);
    }
};

Debugger.prototype.dbg_scripts = function(data) {
    var self = this;
    if (data.action == 'created') {
        _.each(data.scripts, function(script) {
            self.newScript(script);
        });
    }
    else if (data.action == 'resolved') {
        _.each(data.scripts, function(script) {
            self.newScript(script);
        });
    }
    else if (data.action == 'destroyed') {
        _.each(data.scripts, function(script) {
            self.removeScript(script);
        });
    }

};

Debugger.prototype.dbg_log = function(log) {
    log.message = new Date() + log.message;
    this.logMessages.push(log);
    this.dispatchMessage('logAdded', log);
};

Debugger.prototype.dbg_suspended = function(data) {
    this.suspendedData = data;
    this.dispatchMessage('suspended', data);
};

Debugger.prototype.dbg_resumed = function(data) {
    this.suspendedData = null;
    this.dispatchMessage('resumed', data);
};

Debugger.prototype.enable = function(callback) {
    this.enabled = true;
    this.dispatchCommand('enable', null, callback);
};

Debugger.prototype.setOption = function(name, value, callback) {
    this.options[name] = value;
    this.dispatchCommand('option', {name: name, value: value}, callback);
};

Debugger.prototype.getVersion = function(callback) {
    this.dispatchCommand('version', null, callback);
};

Debugger.prototype.getSource = function(scriptId, callback) {
    //logger.debug('Debugger.getSource scriptId: ' + scriptId);
    var script = this.scripts[scriptId];
    if (!script) {
        callback(null);
        return;
    }
    var uri = '' + script.uri;

    uri = uri.replace('app:', 'Resources');
    //logger.debug('uri: ' + uri);
    this.tiProject.readSourceFile(uri, function(err, data) {
        //logger.debug("read project file")
        if (err) {
            logger.debug("error: " + JSON.stringify(err));
            data = null;
        }
        callback(data);
    });

};

Debugger.prototype.setSource = function(scriptId, scriptSource, callback) {
    logger.debug('Debugger.setSource scriptId: ' + scriptId);
    var script = this.scripts[scriptId];
    if (!script) {
        callback(null);
        return;
    }
    var uri = '' + script.uri;

    uri = uri.replace('app:', 'Resources');
    logger.debug('uri: ' + uri);
    this.tiProject.writeSourceFile(uri, scriptSource, function(err, data) {
        //logger.debug("read project file")
        if (err) {
            logger.debug("error: " + JSON.stringify(err));
            data = false;
        }
        callback(true);
    });

};

Debugger.prototype.resume = function(threadId, callback) {
    this.dispatchCommand('resume', {threadId: threadId}, callback);
};

Debugger.prototype.suspend = function(threadId, callback) {
    this.dispatchCommand('suspend', {threadId: threadId}, callback);
};

Debugger.prototype.evaluate = function(threadId, context, expression, callback) {
    this.dispatchCommand('eval', {
        threadId: threadId,
        context: context,
        expression: expression
    }, callback);
};

Debugger.prototype.breakpointId = function(breakpoint) {
    return breakpoint.uri + ':' + breakpoint.line;
};

Debugger.prototype.breakpoint = function(uri, line, condition) {
    return {
        uri: uri,
        line: line,
        state: 1, //enabled
        condition: condition
    };
};

Debugger.prototype.addBreakpoint = function(breakpoint) {
    var breakpointId = this.breakpointId(breakpoint);
    breakpoint.id = breakpointId;

    this.breakpoints[breakpoint.id] = breakpoint;

    return breakpoint;
};

Debugger.prototype.clearBreakpoint = function(breakpointId) {
    delete this.breakpoints[breakpointId];
};

Debugger.prototype.removeBreakpoint = function(breakpointId, callback) {
    var self = this;
    var breakpoint = this.breakpoints[breakpointId];
    if (!breakpoint) {
        return;
    }
    var data = {
        action: 'remove',
        uri: breakpoint.uri,
        line: breakpoint.line
    };

    this.dispatchCommand('breakpoint', data, function(result) {
        self.clearBreakpoint(breakpointId);
        logger.debug('removeBreakpoint callback' + JSON.stringify(result));
        callback(result);
    });
};

Debugger.prototype.createBreakpoint = function(uri, line, condition, callback) {
    var self = this;
    var breakpoint = this.breakpoint(uri, line, condition);
    logger.debug('createBreakpoint: ' + JSON.stringify(breakpoint));
    var data = {
        action: 'create'
    };
    _.extend(data, breakpoint);
    delete data.id; //

    this.dispatchCommand('breakpoint', data, function(result) {
        result.args.breakpoint = self.addBreakpoint(breakpoint);
        logger.debug('createBreakpoint callback' + JSON.stringify(result));
        callback(result);
    });
};

Debugger.prototype.getFrames = function(threadId, callback) {
    this.dispatchCommand('frames', {
        threadId: threadId
    }, callback);
};

Debugger.prototype.getFrameVariables = function(threadId, frame, callback) {
    this.dispatchCommand('variables', {
        threadId: threadId,
        frameId: frame
    }, callback);
};

Debugger.prototype.getVariableDetails = function(threadId, variable, callback) {
    this.dispatchCommand('details', {
        threadId: threadId,
        variableName: variable
    }, callback);
};

Debugger.prototype.stepInto = function(threadId, callback) {
    this.dispatchCommand('stepInto', {
        threadId: threadId
    }, callback);
};

Debugger.prototype.stepOver = function(threadId, callback) {
    this.dispatchCommand('stepOver', {
        threadId: threadId
    }, callback);
};

Debugger.prototype.stepReturn = function(threadId, callback) {
    this.dispatchCommand('stepReturn', {
        threadId: threadId
    }, callback);
};

Debugger.prototype.notifyBackendMessage = function(msg) {
    logger.debug("notifyBackendMessage: " + JSON.stringify(msg));
    if (this[msg.message]) {
        logger.debug(this[msg.message]);
        this[msg.message].call(this, msg.args);
    }

};

module.exports = Debugger;
<commit_msg>fixed wrong listing of platform-specific files (issue #16)<commit_after>var util = require('util'),
    EventEmitter = require('events').EventEmitter,
    logger = require('../logger'),
    _ = require('underscore');

var Debugger = function(debuggerBackend, tiProject) {
    this.backend = debuggerBackend;
    this.threads = {};
    this.scripts = {};
    this.scriptUriToIdMap = {};
    this.breakpoints = {};
    this.logMessages = [];
    this.options = {};
    this.tiProject = tiProject;
    var self = this;
    debuggerBackend.on('message', function(msg) {
        //self.notifyBackendMessage(message);
        //logger.debug("notifyBackendMessage: " + JSON.stringify(msg));
        var method = 'dbg_' + msg.message;
        if (self[method]) {
            self[method].call(self, msg.args);
        }
    });

    this.enumerateScripts();
};

util.inherits(Debugger, EventEmitter);

Debugger.prototype.newScriptId = function() {
    if (!this.lastScriptId) {
        this.lastScriptId = 0;
    }
    this.lastScriptId++;
    return this.lastScriptId;
};

Debugger.prototype.enumerateScripts = function() {
    var self = this;
    this.tiProject.findResourceFilesOfType('.js', function(err, fileName) {
        var scriptId = self.newScriptId();
        self.addScript({
            scriptId: scriptId,
            uri: fileName.replace(self.tiProject.projectFile('Resources'), 'app:'),
            "function": '',
            line: 0,
            linecount: 0
        });
    });
};

Debugger.prototype.dispatchMessage = function(message, data) {
    var msg = {
        message: message,
        data: data
    };
    this.emit('message', msg);
};

Debugger.prototype.dispatchCommand = function(command, args, callback) {
    if (!this.backend) {
        callback();
        return;
    }

    this.backend.sendCommand({
        command: command,
        args: args
    }, callback);
};

Debugger.prototype.newThread = function(thread) {
    this.threads[thread.threadId] = thread;
    this.dispatchMessage('threadAdded', thread);
};

Debugger.prototype.removeThread = function(thread) {
    thread = this.threads[thread.threadId];
    delete this.threads[thread.threadId];
    this.dispatchMessage('threadRemoved', thread);
};

Debugger.prototype.scriptFromUri = function(uri) {
    var platformUris = _.map(['/iphone', ''], function(platformDir) {
        return uri.replace('app:', 'app:' + platformDir);
    });
    var which =  _.find(platformUris, function(platformSpecificUri) {
        return this.scriptUriToIdMap[platformSpecificUri] != null;
    }, this);

    var scriptId = this.scriptUriToIdMap[which];
    if (!scriptId) {
        return null;
    }
    return this.scripts[scriptId];
};

Debugger.prototype.addScript = function(script) {
    var scriptId = '' + script.scriptId;
    this.scripts[scriptId] = script;
    this.scriptUriToIdMap[script.uri] = scriptId;
    this.dispatchMessage('scriptAdded', script);
};

Debugger.prototype.newScript = function(script) {
    var s = this.scriptFromUri(script.uri);
    if (!s) {
        script.scriptId += '';
        this.addScript(script);
    }
};

Debugger.prototype.removeScript = function(script) {
    script = this.scripts[script.scriptId];
    delete this.scripts[script.scriptId];
    delete this.scriptUriToIdMap[script.uri];
    this.dispatchMessage('scriptRemoved', script);
};

Debugger.prototype.dbg_threads = function(data) {
    if (data.action == 'created') {
        this.newThread({
            threadId: data.threadId,
            name: data.name
        });
    }
    else if (data.action == 'destroyed') {
        this.removeThread(data.id);
    }
};

Debugger.prototype.dbg_scripts = function(data) {
    var self = this;
    if (data.action == 'created') {
        _.each(data.scripts, function(script) {
            self.newScript(script);
        });
    }
    else if (data.action == 'resolved') {
        _.each(data.scripts, function(script) {
            self.newScript(script);
        });
    }
    else if (data.action == 'destroyed') {
        _.each(data.scripts, function(script) {
            self.removeScript(script);
        });
    }

};

Debugger.prototype.dbg_log = function(log) {
    log.message = new Date() + log.message;
    this.logMessages.push(log);
    this.dispatchMessage('logAdded', log);
};

Debugger.prototype.dbg_suspended = function(data) {
    this.suspendedData = data;
    this.dispatchMessage('suspended', data);
};

Debugger.prototype.dbg_resumed = function(data) {
    this.suspendedData = null;
    this.dispatchMessage('resumed', data);
};

Debugger.prototype.enable = function(callback) {
    this.enabled = true;
    this.dispatchCommand('enable', null, callback);
};

Debugger.prototype.setOption = function(name, value, callback) {
    this.options[name] = value;
    this.dispatchCommand('option', {name: name, value: value}, callback);
};

Debugger.prototype.getVersion = function(callback) {
    this.dispatchCommand('version', null, callback);
};

Debugger.prototype.getSource = function(scriptId, callback) {
    //logger.debug('Debugger.getSource scriptId: ' + scriptId);
    var script = this.scripts[scriptId];
    if (!script) {
        callback(null);
        return;
    }
    var uri = '' + script.uri;

    uri = uri.replace('app:', 'Resources');
    //logger.debug('uri: ' + uri);
    this.tiProject.readSourceFile(uri, function(err, data) {
        //logger.debug("read project file")
        if (err) {
            logger.debug("error: " + JSON.stringify(err));
            data = null;
        }
        callback(data);
    });

};

Debugger.prototype.setSource = function(scriptId, scriptSource, callback) {
    logger.debug('Debugger.setSource scriptId: ' + scriptId);
    var script = this.scripts[scriptId];
    if (!script) {
        callback(null);
        return;
    }
    var uri = '' + script.uri;

    uri = uri.replace('app:', 'Resources');
    logger.debug('uri: ' + uri);
    this.tiProject.writeSourceFile(uri, scriptSource, function(err, data) {
        //logger.debug("read project file")
        if (err) {
            logger.debug("error: " + JSON.stringify(err));
            data = false;
        }
        callback(true);
    });

};

Debugger.prototype.resume = function(threadId, callback) {
    this.dispatchCommand('resume', {threadId: threadId}, callback);
};

Debugger.prototype.suspend = function(threadId, callback) {
    this.dispatchCommand('suspend', {threadId: threadId}, callback);
};

Debugger.prototype.evaluate = function(threadId, context, expression, callback) {
    this.dispatchCommand('eval', {
        threadId: threadId,
        context: context,
        expression: expression
    }, callback);
};

Debugger.prototype.breakpointId = function(breakpoint) {
    return breakpoint.uri + ':' + breakpoint.line;
};

Debugger.prototype.breakpoint = function(uri, line, condition) {
    return {
        uri: uri,
        line: line,
        state: 1, //enabled
        condition: condition
    };
};

Debugger.prototype.addBreakpoint = function(breakpoint) {
    var breakpointId = this.breakpointId(breakpoint);
    breakpoint.id = breakpointId;

    this.breakpoints[breakpoint.id] = breakpoint;

    return breakpoint;
};

Debugger.prototype.clearBreakpoint = function(breakpointId) {
    delete this.breakpoints[breakpointId];
};

Debugger.prototype.removeBreakpoint = function(breakpointId, callback) {
    var self = this;
    var breakpoint = this.breakpoints[breakpointId];
    if (!breakpoint) {
        return;
    }
    var data = {
        action: 'remove',
        uri: breakpoint.uri,
        line: breakpoint.line
    };

    this.dispatchCommand('breakpoint', data, function(result) {
        self.clearBreakpoint(breakpointId);
        logger.debug('removeBreakpoint callback' + JSON.stringify(result));
        callback(result);
    });
};

Debugger.prototype.createBreakpoint = function(uri, line, condition, callback) {
    var self = this;
    var breakpoint = this.breakpoint(uri, line, condition);
    logger.debug('createBreakpoint: ' + JSON.stringify(breakpoint));
    var data = {
        action: 'create'
    };
    _.extend(data, breakpoint);
    delete data.id; //

    this.dispatchCommand('breakpoint', data, function(result) {
        result.args.breakpoint = self.addBreakpoint(breakpoint);
        logger.debug('createBreakpoint callback' + JSON.stringify(result));
        callback(result);
    });
};

Debugger.prototype.getFrames = function(threadId, callback) {
    this.dispatchCommand('frames', {
        threadId: threadId
    }, callback);
};

Debugger.prototype.getFrameVariables = function(threadId, frame, callback) {
    this.dispatchCommand('variables', {
        threadId: threadId,
        frameId: frame
    }, callback);
};

Debugger.prototype.getVariableDetails = function(threadId, variable, callback) {
    this.dispatchCommand('details', {
        threadId: threadId,
        variableName: variable
    }, callback);
};

Debugger.prototype.stepInto = function(threadId, callback) {
    this.dispatchCommand('stepInto', {
        threadId: threadId
    }, callback);
};

Debugger.prototype.stepOver = function(threadId, callback) {
    this.dispatchCommand('stepOver', {
        threadId: threadId
    }, callback);
};

Debugger.prototype.stepReturn = function(threadId, callback) {
    this.dispatchCommand('stepReturn', {
        threadId: threadId
    }, callback);
};

Debugger.prototype.notifyBackendMessage = function(msg) {
    logger.debug("notifyBackendMessage: " + JSON.stringify(msg));
    if (this[msg.message]) {
        logger.debug(this[msg.message]);
        this[msg.message].call(this, msg.args);
    }

};

module.exports = Debugger;
<|endoftext|>


<commit_before>// Given a hash of GeoJSON objects, transforms any properties on features using
// the specified transform function. The function is invoked for each existing
// property on the current feature, being passed the new properties hash, the
// property name, and the property value. The function is then expected to
// assign a new value to the given property hash if the feature is to be
// retained and return true. Or, to skip the property, do nothing and return
// false. If no properties are propagated to the new properties hash, the
// properties hash will be deleted from the current feature.
module.exports = function(objects, id) {
  if (arguments.length < 2) id = function(d) { return d.id; };

  function idObject(object) {
    if (object && idObjectType.hasOwnProperty(object.type)) idObjectType[object.type](object);
  }

  function idFeature(feature) {
    var i = id(feature);
    if (i == null) delete feature.id;
    else feature.id = i;
  }

  var idObjectType = {
    Feature: idFeature,
    FeatureCollection: function(collection) { collection.features.forEach(idFeature); }
  };

  for (var key in objects) {
    idObject(objects[key]);
  }

  return objects;
};
<commit_msg>Fix comment.<commit_after>// Given a hash of GeoJSON objects and an id function, invokes the id function
// to compute a new id for each object that is a feature. The function is passed
// the feature and is expected to return the new feature id, or null if the
// feature should not have an id.
module.exports = function(objects, id) {
  if (arguments.length < 2) id = function(d) { return d.id; };

  function idObject(object) {
    if (object && idObjectType.hasOwnProperty(object.type)) idObjectType[object.type](object);
  }

  function idFeature(feature) {
    var i = id(feature);
    if (i == null) delete feature.id;
    else feature.id = i;
  }

  var idObjectType = {
    Feature: idFeature,
    FeatureCollection: function(collection) { collection.features.forEach(idFeature); }
  };

  for (var key in objects) {
    idObject(objects[key]);
  }

  return objects;
};
<|endoftext|>


<commit_before>var _ = require('lodash');
var Promise = require('bluebird');
var query = require('../query');

module.exports = function (options) {
    options = options || {};
    var stopAssetsMatcher = function () {
        return false;
    };

    if (options.stopAssets) {
        stopAssetsMatcher = query.queryObjToMatcherFunction(options.stopAssets);
    }
    return function populate(assetGraph) {
        var followRelationsMatcher = query.queryObjToMatcherFunction(options.followRelations || assetGraph.followRelations),
            assetQueue = assetGraph.findAssets(_.extend({isInline: false}, options.startAssets || options.from)),
            maxWaitingCallbacks = options.concurrency || 100,
            numWaitingCallbacks = 0,
            firstErrorOrNull = null;

        function processAsset(asset) {
            return asset.load().then(function () {
                return Promise.map(asset.externalRelations, function (originalRelation) {
                    var resolvedAssetConfig;
                    try {
                        resolvedAssetConfig = originalRelation.resolve();
                    } catch (err) {
                        assetGraph.emit('warn', err);
                    }
                    if (resolvedAssetConfig && resolvedAssetConfig.to.isResolved && followRelationsMatcher(resolvedAssetConfig, assetGraph)) {
                        return assetGraph.ensureAssetConfigHasType(resolvedAssetConfig.to).then(function () {
                            var targetAsset;
                            if (resolvedAssetConfig.to.url) {
                                // See if the target asset is already in the graph by looking up its url:
                                var targetAssets = assetGraph.findAssets({
                                    url: resolvedAssetConfig.to.url
                                });
                                // If multiple assets share the url, prefer the one that was added last (should be customizable?):
                                if (targetAssets.length) {
                                    targetAsset = targetAssets[targetAssets.length - 1];
                                }
                            }
                            if (targetAsset) {
                                resolvedAssetConfig.to = targetAsset;
                                resolvedAssetConfig.refreshHref();
                            } else {
                                resolvedAssetConfig.to = assetGraph.createAsset(resolvedAssetConfig.to);
                                assetGraph.addAsset(resolvedAssetConfig.to);
                                if (!stopAssetsMatcher(resolvedAssetConfig.to)) {
                                    assetQueue.push(resolvedAssetConfig.to);
                                }
                            }
                        }).caught(function (err) {
                            err.message = err.message || err.code || err.name;
                            err.message += '\nIncluding asset [' + resolvedAssetConfig.type + ']: ' + resolvedAssetConfig.from.nonInlineAncestor.url;
                            err.asset = resolvedAssetConfig.to;
                            err.relation = resolvedAssetConfig;
                            assetGraph.emit('warn', err);
                        });
                    }
                });
            }, function (err) {
                err.message = err.message || err.code || err.name;
                var includingAssetUrls = asset.incomingRelations.map(function (incomingRelation) {
                    return incomingRelation.from.urlOrDescription;
                });
                if (includingAssetUrls.length > 0) {
                    err.message += '\nIncluding assets:\n    ' + includingAssetUrls.join('\n    ') + '\n';
                }
                err.asset = asset;
                assetGraph.emit('warn', err);
            });
        }

        return (function proceed() {
            if (!firstErrorOrNull) {
                var promises = [];
                while (assetQueue.length && numWaitingCallbacks < maxWaitingCallbacks) {
                    numWaitingCallbacks += 1;
                    promises.push(processAsset(assetQueue.shift()).caught(function (err) {
                        firstErrorOrNull = firstErrorOrNull || err;
                    }));
                }
                if (promises.length > 0) {
                    return Promise.all(promises).then(function () {
                        numWaitingCallbacks -= promises.length;
                        return proceed();
                    });
                }
            }
        }());
    };
};
<commit_msg>populate transform: Degrade 'warn' event to 'info' when there's trouble loading a source map.<commit_after>var _ = require('lodash');
var Promise = require('bluebird');
var query = require('../query');

module.exports = function (options) {
    options = options || {};
    var stopAssetsMatcher = function () {
        return false;
    };

    if (options.stopAssets) {
        stopAssetsMatcher = query.queryObjToMatcherFunction(options.stopAssets);
    }
    return function populate(assetGraph) {
        var followRelationsMatcher = query.queryObjToMatcherFunction(options.followRelations || assetGraph.followRelations),
            assetQueue = assetGraph.findAssets(_.extend({isInline: false}, options.startAssets || options.from)),
            maxWaitingCallbacks = options.concurrency || 100,
            numWaitingCallbacks = 0,
            firstErrorOrNull = null;

        function processAsset(asset) {
            return asset.load().then(function () {
                return Promise.map(asset.externalRelations, function (originalRelation) {
                    var resolvedAssetConfig;
                    try {
                        resolvedAssetConfig = originalRelation.resolve();
                    } catch (err) {
                        assetGraph.emit('warn', err);
                    }
                    if (resolvedAssetConfig && resolvedAssetConfig.to.isResolved && followRelationsMatcher(resolvedAssetConfig, assetGraph)) {
                        return assetGraph.ensureAssetConfigHasType(resolvedAssetConfig.to).then(function () {
                            var targetAsset;
                            if (resolvedAssetConfig.to.url) {
                                // See if the target asset is already in the graph by looking up its url:
                                var targetAssets = assetGraph.findAssets({
                                    url: resolvedAssetConfig.to.url
                                });
                                // If multiple assets share the url, prefer the one that was added last (should be customizable?):
                                if (targetAssets.length) {
                                    targetAsset = targetAssets[targetAssets.length - 1];
                                }
                            }
                            if (targetAsset) {
                                resolvedAssetConfig.to = targetAsset;
                                resolvedAssetConfig.refreshHref();
                            } else {
                                resolvedAssetConfig.to = assetGraph.createAsset(resolvedAssetConfig.to);
                                assetGraph.addAsset(resolvedAssetConfig.to);
                                if (!stopAssetsMatcher(resolvedAssetConfig.to)) {
                                    assetQueue.push(resolvedAssetConfig.to);
                                }
                            }
                        }).caught(function (err) {
                            err.message = err.message || err.code || err.name;
                            err.message += '\nIncluding asset [' + resolvedAssetConfig.type + ']: ' + resolvedAssetConfig.from.nonInlineAncestor.url;
                            err.asset = resolvedAssetConfig.to;
                            err.relation = resolvedAssetConfig;
                            assetGraph.emit('warn', err);
                        });
                    }
                });
            }, function (err) {
                err.message = err.message || err.code || err.name;
                var includingAssetUrls = asset.incomingRelations.map(function (incomingRelation) {
                    return incomingRelation.from.urlOrDescription;
                });
                if (includingAssetUrls.length > 0) {
                    err.message += '\nIncluding assets:\n    ' + includingAssetUrls.join('\n    ') + '\n';
                }
                err.asset = asset;

                if (asset.incomingRelations.length > 0 && asset.incomingRelations.every(relation => /SourceMappingUrl$/.test(relation.type))) {
                    assetGraph.emit('info', err);
                } else {
                    assetGraph.emit('warn', err);
                }
            });
        }

        return (function proceed() {
            if (!firstErrorOrNull) {
                var promises = [];
                while (assetQueue.length && numWaitingCallbacks < maxWaitingCallbacks) {
                    numWaitingCallbacks += 1;
                    promises.push(processAsset(assetQueue.shift()).caught(function (err) {
                        firstErrorOrNull = firstErrorOrNull || err;
                    }));
                }
                if (promises.length > 0) {
                    return Promise.all(promises).then(function () {
                        numWaitingCallbacks -= promises.length;
                        return proceed();
                    });
                }
            }
        }());
    };
};
<|endoftext|>


<commit_before>(function ($) {
  // register namespace
  $.extend(true, window, {
    "Slick": {
      "CheckboxSelectColumn": CheckboxSelectColumn
    }
  });

  function CheckboxSelectColumn(options) {
    var _grid;
    var _self = this;
    var _handler = new Slick.EventHandler();
    var _selectedRowsLookup = {};
    var _defaults = {
      columnId: "_checkbox_selector",
      cssClass: null,
      toolTip: "Select/Deselect All",
      width: 30
    };

    var _options = $.extend(true, {}, _defaults, options);

    function init(grid) {
      _grid = grid;
      _handler
        .subscribe(_grid.onSelectedRowsChanged, handleSelectedRowsChanged)
        .subscribe(_grid.onClick, handleClick)
        .subscribe(_grid.onHeaderClick, handleHeaderClick)
        .subscribe(_grid.onKeyDown, handleKeyDown);
    }

    function destroy() {
      _handler.unsubscribeAll();
    }

    function handleSelectedRowsChanged(e, args) {
      var selectedRows = _grid.getSelectedRows();
      var lookup = {}, row, i;
      for (i = 0; i < selectedRows.length; i++) {
        row = selectedRows[i];
        lookup[row] = true;
        if (lookup[row] !== _selectedRowsLookup[row]) {
          _grid.invalidateRow(row);
          delete _selectedRowsLookup[row];
        }
      }
      for (i in _selectedRowsLookup) {
        _grid.invalidateRow(i);
      }
      _selectedRowsLookup = lookup;
      _grid.render();

      if (selectedRows.length && selectedRows.length == _grid.getDataLength()) {
        _grid.updateColumnHeader(_options.columnId, "<input type='checkbox' checked='checked'>", _options.toolTip);
      } else {
        _grid.updateColumnHeader(_options.columnId, "<input type='checkbox'>", _options.toolTip);
      }
    }

    function handleKeyDown(e, args) {
      if (e.which == 32) {
        if (_grid.getColumns()[args.cell].id === _options.columnId) {
          // if editing, try to commit
          if (!_grid.getEditorLock().isActive() || _grid.getEditorLock().commitCurrentEdit()) {
            toggleRowSelection(args.row);
          }
          e.preventDefault();
          e.stopImmediatePropagation();
        }
      }
    }

    function handleClick(e, args) {
      // clicking on a row select checkbox
      if (_grid.getColumns()[args.cell].id === _options.columnId && $(e.target).is(":checkbox")) {
        // if editing, try to commit
        if (_grid.getEditorLock().isActive() && !_grid.getEditorLock().commitCurrentEdit()) {
          e.preventDefault();
          e.stopImmediatePropagation();
          return;
        }

        toggleRowSelection(args.row);
        e.stopPropagation();
        e.stopImmediatePropagation();
      }
    }

    function toggleRowSelection(row) {
      if (_selectedRowsLookup[row]) {
        _grid.setSelectedRows($.grep(_grid.getSelectedRows(), function (n) {
          return n != row
        }));
      } else {
        _grid.setSelectedRows(_grid.getSelectedRows().concat(row));
      }
    }

    function handleHeaderClick(e, args) {
      if (args.column.id == _options.columnId && $(e.target).is(":checkbox")) {
        // if editing, try to commit
        if (_grid.getEditorLock().isActive() && !_grid.getEditorLock().commitCurrentEdit()) {
          e.preventDefault();
          e.stopImmediatePropagation();
          return;
        }

        if ($(e.target).is(":checked")) {
          var rows = [];
          for (var i = 0; i < _grid.getDataLength(); i++) {
            rows.push(i);
          }
          _grid.setSelectedRows(rows);
        } else {
          _grid.setSelectedRows([]);
        }
        e.stopPropagation();
        e.stopImmediatePropagation();
      }
    }

    function getColumnDefinition() {
      return {
        id: _options.columnId,
        name: "<input type='checkbox'>",
        toolTip: _options.toolTip,
        field: "sel",
        width: _options.width,
        resizable: false,
        sortable: false,
        cssClass: _options.cssClass,
        formatter: checkboxSelectionFormatter
      };
    }

    function checkboxSelectionFormatter(row, cell, value, columnDef, dataContext) {
      if (dataContext) {
        return _selectedRowsLookup[row]
            ? "<input type='checkbox' checked='checked'>"
            : "<input type='checkbox'>";
      }
      return null;
    }

    $.extend(this, {
      "init": init,
      "destroy": destroy,

      "getColumnDefinition": getColumnDefinition
    });
  }
})(jQuery);<commit_msg>Have Slick.CheckboxSelectColumn respect getItemMetadata(x).selectable.<commit_after>(function ($) {
  // register namespace
  $.extend(true, window, {
    "Slick": {
      "CheckboxSelectColumn": CheckboxSelectColumn
    }
  });

  function CheckboxSelectColumn(options) {
    var _grid;
    var _self = this;
    var _handler = new Slick.EventHandler();
    var _selectedRowsLookup = {};
    var _defaults = {
      columnId: "_checkbox_selector",
      cssClass: null,
      toolTip: "Select/Deselect All",
      width: 30
    };

    var _options = $.extend(true, {}, _defaults, options);

    function init(grid) {
      _grid = grid;
      _handler
        .subscribe(_grid.onSelectedRowsChanged, handleSelectedRowsChanged)
        .subscribe(_grid.onClick, handleClick)
        .subscribe(_grid.onHeaderClick, handleHeaderClick)
        .subscribe(_grid.onKeyDown, handleKeyDown);
    }

    function destroy() {
      _handler.unsubscribeAll();
    }

    function handleSelectedRowsChanged(e, args) {
      var selectedRows = _grid.getSelectedRows();
      var data = _grid.getData();
      var selectableRowCount = 0;
      var lookup = {}, row, i, rowSelectable;
      for (i = 0; i < _grid.getDataLength(); i++) {
        rowSelectable = data.getItemMetadata(i).selectable != false;
        if (rowSelectable) {
          selectableRowCount += 1;
        }
      }
      for (i = 0; i < selectedRows.length; i++) {
        row = selectedRows[i];
        lookup[row] = true;
        if (lookup[row] !== _selectedRowsLookup[row]) {
          _grid.invalidateRow(row);
          delete _selectedRowsLookup[row];
        }
      }
      for (i in _selectedRowsLookup) {
        _grid.invalidateRow(i);
      }
      _selectedRowsLookup = lookup;
      _grid.render();

      if (selectedRows.length == selectableRowCount) {
        _grid.updateColumnHeader(_options.columnId, "<input type='checkbox' checked='checked'>", _options.toolTip);
      } else {
        _grid.updateColumnHeader(_options.columnId, "<input type='checkbox'>", _options.toolTip);
      }
    }

    function handleKeyDown(e, args) {
      if (e.which == 32) {
        if (_grid.getColumns()[args.cell].id === _options.columnId) {
          // if editing, try to commit
          if (!_grid.getEditorLock().isActive() || _grid.getEditorLock().commitCurrentEdit()) {
            toggleRowSelection(args.row);
          }
          e.preventDefault();
          e.stopImmediatePropagation();
        }
      }
    }

    function handleClick(e, args) {
      // clicking on a row select checkbox
      if (_grid.getColumns()[args.cell].id === _options.columnId && $(e.target).is(":checkbox")) {
        // if editing, try to commit
        if (_grid.getEditorLock().isActive() && !_grid.getEditorLock().commitCurrentEdit()) {
          e.preventDefault();
          e.stopImmediatePropagation();
          return;
        }

        toggleRowSelection(args.row);
        e.stopPropagation();
        e.stopImmediatePropagation();
      }
    }

    function toggleRowSelection(row) {
      var data = _grid.getData(),
          rowSelectable = data.getItemMetadata(row).selectable != false;
      if (_selectedRowsLookup[row]) {
        _grid.setSelectedRows($.grep(_grid.getSelectedRows(), function (n) {
          return n != row
        }));
      } else if (rowSelectable) {
        _grid.setSelectedRows(_grid.getSelectedRows().concat(row));
      }
    }

    function handleHeaderClick(e, args) {
      if (args.column.id == _options.columnId && $(e.target).is(":checkbox")) {
        // if editing, try to commit
        if (_grid.getEditorLock().isActive() && !_grid.getEditorLock().commitCurrentEdit()) {
          e.preventDefault();
          e.stopImmediatePropagation();
          return;
        }

        if ($(e.target).is(":checked")) {
          var rows = [],
              data = _grid.getData(),
              rowSelectable;
          for (var i = 0; i < _grid.getDataLength(); i++) {
            rowSelectable = data.getItemMetadata(i).selectable != false;
            if (rowSelectable) {
              rows.push(i);
            }
          }
          _grid.setSelectedRows(rows);
        } else {
          _grid.setSelectedRows([]);
        }
        e.stopPropagation();
        e.stopImmediatePropagation();
      }
    }

    function getColumnDefinition() {
      return {
        id: _options.columnId,
        name: "<input type='checkbox'>",
        toolTip: _options.toolTip,
        field: "sel",
        width: _options.width,
        resizable: false,
        sortable: false,
        cssClass: _options.cssClass,
        formatter: checkboxSelectionFormatter
      };
    }

    function checkboxSelectionFormatter(row, cell, value, columnDef, dataContext) {
      if (dataContext) {
        return _selectedRowsLookup[row]
            ? "<input type='checkbox' checked='checked'>"
            : "<input type='checkbox'>";
      }
      return null;
    }

    $.extend(this, {
      "init": init,
      "destroy": destroy,

      "getColumnDefinition": getColumnDefinition
    });
  }
})(jQuery);<|endoftext|>


<commit_before>(function ($) {
  // register namespace
  $.extend(true, window, {
    "Slick": {
      "CheckboxSelectColumn": CheckboxSelectColumn
    }
  });

  function CheckboxSelectColumn(options) {
    var _grid;
    var _selectAll_UID = createUID();
    var _handler = new Slick.EventHandler();
    var _selectedRowsLookup = {};
    var _defaults = {
      columnId: "_checkbox_selector",
      cssClass: null,
      hideSelectAllCheckbox: false,
      toolTip: "Select/Deselect All",
      width: 30,
      showInColumnTitleRow: true,
      showInFilterHeaderRow: false
    };
    var _isSelectAllChecked = false;

    var _options = $.extend(true, {}, _defaults, options);

    function init(grid) {
      _grid = grid;
      _handler
      .subscribe(_grid.onSelectedRowsChanged, handleSelectedRowsChanged)
      .subscribe(_grid.onClick, handleClick)
      .subscribe(_grid.onKeyDown, handleKeyDown);

      if (_options.showInFilterHeaderRow) {
        addCheckboxToFilterHeaderRow(grid);
      }
      if (_options.showInColumnTitleRow) {
        _handler.subscribe(_grid.onHeaderClick, handleHeaderClick)
      }
    }

    function destroy() {
      _handler.unsubscribeAll();
    }

    function getOptions() {
      return _options;
    }

    function setOptions(options) {
      _options = $.extend(true, {}, _options, options);

      if (_options.hideSelectAllCheckbox) {
        hideSelectAllFromColumnHeaderTitleRow();
        hideSelectAllFromColumnHeaderFilterRow();
      } else {
        if (_options.showInColumnTitleRow) {
          if (_isSelectAllChecked) {
            _grid.updateColumnHeader(_options.columnId, "<input id='header-selector" + _selectAll_UID + "' type='checkbox' checked='checked'>", _options.toolTip);
          } else {
            _grid.updateColumnHeader(_options.columnId, "<input id='header-selector" + _selectAll_UID + "' type='checkbox'>", _options.toolTip);
          }
        } else {
          hideSelectAllFromColumnHeaderTitleRow();
        }

        if (_options.showInFilterHeaderRow) {
          var selectAllContainer = $("#filter-checkbox-selectall-container");
          selectAllContainer.show();
          selectAllContainer.find('input[type="checkbox"]').prop("checked", _isSelectAllChecked);
        } else {
          hideSelectAllFromColumnHeaderFilterRow();
        }
      }
    }

    function hideSelectAllFromColumnHeaderTitleRow() {
      _grid.updateColumnHeader(_options.columnId, "", "");
    }

    function hideSelectAllFromColumnHeaderFilterRow() {
      $("#filter-checkbox-selectall-container").hide();
    }

    function handleSelectedRowsChanged(e, args) {
      var selectedRows = _grid.getSelectedRows();
      var lookup = {}, row, i;
      for (i = 0; i < selectedRows.length; i++) {
        row = selectedRows[i];
        lookup[row] = true;
        if (lookup[row] !== _selectedRowsLookup[row]) {
          _grid.invalidateRow(row);
          delete _selectedRowsLookup[row];
        }
      }
      for (i in _selectedRowsLookup) {
        _grid.invalidateRow(i);
      }
      _selectedRowsLookup = lookup;
      _grid.render();
      _isSelectAllChecked = selectedRows.length && selectedRows.length == _grid.getDataLength();

      if (_options.showInColumnTitleRow && !_options.hideSelectAllCheckbox) {
        if (_isSelectAllChecked) {
          _grid.updateColumnHeader(_options.columnId, "<input id='header-selector" + _selectAll_UID + "' type='checkbox' checked='checked'>", _options.toolTip);
        } else {
          _grid.updateColumnHeader(_options.columnId, "<input id='header-selector" + _selectAll_UID + "' type='checkbox'>", _options.toolTip);
        }
      }
      if (_options.showInFilterHeaderRow) {
        var selectAllElm = $("#header-filter-selector" + _selectAll_UID);
        selectAllElm.prop("checked", _isSelectAllChecked);
      }
    }

    function handleKeyDown(e, args) {
      if (e.which == 32) {
        if (_grid.getColumns()[args.cell].id === _options.columnId) {
          // if editing, try to commit
          if (!_grid.getEditorLock().isActive() || _grid.getEditorLock().commitCurrentEdit()) {
            toggleRowSelection(args.row);
          }
          e.preventDefault();
          e.stopImmediatePropagation();
        }
      }
    }

    function handleClick(e, args) {
      // clicking on a row select checkbox
      if (_grid.getColumns()[args.cell].id === _options.columnId && $(e.target).is(":checkbox")) {
        // if editing, try to commit
        if (_grid.getEditorLock().isActive() && !_grid.getEditorLock().commitCurrentEdit()) {
          e.preventDefault();
          e.stopImmediatePropagation();
          return;
        }

        toggleRowSelection(args.row);
        e.stopPropagation();
        e.stopImmediatePropagation();
      }
    }

    function toggleRowSelection(row) {
      if (_selectedRowsLookup[row]) {
        _grid.setSelectedRows($.grep(_grid.getSelectedRows(), function (n) {
          return n != row
        }));
      } else {
        _grid.setSelectedRows(_grid.getSelectedRows().concat(row));
      }
      _grid.setActiveCell(row, getCheckboxColumnCellIndex());
      _grid.focus();
    }

    function selectRows(rowArray) {
      var i, l=rowArray.length, addRows = [];
      for(i=0; i<l; i++) {
        if (!_selectedRowsLookup[rowArray[i]]) {
          addRows[addRows.length] = rowArray[i];
        }
      }
      _grid.setSelectedRows(_grid.getSelectedRows().concat(addRows));
    }

    function deSelectRows(rowArray) {
      var i, l=rowArray.length, removeRows = [];
      for(i=0; i<l; i++) {
        if (_selectedRowsLookup[rowArray[i]]) {
          removeRows[removeRows.length] = rowArray[i];
        }
      }
      _grid.setSelectedRows($.grep(_grid.getSelectedRows(), function (n) {
        return removeRows.indexOf(n)<0
      }));
    }

    function handleHeaderClick(e, args) {
      if (args.column.id == _options.columnId && $(e.target).is(":checkbox")) {
        // if editing, try to commit
        if (_grid.getEditorLock().isActive() && !_grid.getEditorLock().commitCurrentEdit()) {
          e.preventDefault();
          e.stopImmediatePropagation();
          return;
        }

        if ($(e.target).is(":checked")) {
          var rows = [];
          for (var i = 0; i < _grid.getDataLength(); i++) {
            rows.push(i);
          }
          _grid.setSelectedRows(rows);
        } else {
          _grid.setSelectedRows([]);
        }
        e.stopPropagation();
        e.stopImmediatePropagation();
      }
    }

    var _checkboxColumnCellIndex = null;

    function getCheckboxColumnCellIndex() {
      if (_checkboxColumnCellIndex === null) {
        _checkboxColumnCellIndex = 0;
        var colArr = _grid.getColumns();
        for (var i=0; i < colArr.length; i++) {
          if (colArr[i].id == _options.columnId) {
            _checkboxColumnCellIndex = i;
          }
        }
      }
      return _checkboxColumnCellIndex;
    }

    function getColumnDefinition() {
      return {
        id: _options.columnId,
        name: (_options.hideSelectAllCheckbox || !_options.showInColumnTitleRow) ? "" : "<input id='header-selector" + _selectAll_UID + "' type='checkbox'>",
        toolTip: _options.toolTip,
        field: "sel",
        width: _options.width,
        resizable: false,
        sortable: false,
        cssClass: _options.cssClass,
        hideSelectAllCheckbox: _options.hideSelectAllCheckbox,
        formatter: checkboxSelectionFormatter
      };
    }

    function addCheckboxToFilterHeaderRow(grid) {
      grid.onHeaderRowCellRendered.subscribe(function(e, args) {
        if (args.column.field === "sel") {
          $(args.node).empty();
          $("<input id='header-filter-selector" + _selectAll_UID + "' type='checkbox'>")
            .appendTo(args.node)
            .on('click', function(evnt) {
              handleHeaderClick(evnt, args)
            });
        }
      });
    }

    function createUID() {
      return Math.round(10000000 * Math.random());
    }

    function checkboxSelectionFormatter(row, cell, value, columnDef, dataContext) {
      var UID = createUID() + row;

      if (dataContext) {
        return _selectedRowsLookup[row]
            ? "<input id='selector" + UID + "' type='checkbox' checked='checked'>"
            : "<input id='selector" + UID + "' type='checkbox'>";
      }
      return null;
    }

    $.extend(this, {
      "init": init,
      "destroy": destroy,
      "deSelectRows": deSelectRows,
      "selectRows": selectRows,
      "getColumnDefinition": getColumnDefinition,
      "getOptions": getOptions,
      "setOptions": setOptions,
    });
  }
})(jQuery);<commit_msg>fix handle click from title not always working when using setOptions<commit_after>(function ($) {
  // register namespace
  $.extend(true, window, {
    "Slick": {
      "CheckboxSelectColumn": CheckboxSelectColumn
    }
  });

  function CheckboxSelectColumn(options) {
    var _grid;
    var _selectAll_UID = createUID();
    var _handler = new Slick.EventHandler();
    var _selectedRowsLookup = {};
    var _defaults = {
      columnId: "_checkbox_selector",
      cssClass: null,
      hideSelectAllCheckbox: false,
      toolTip: "Select/Deselect All",
      width: 30,
      showInColumnTitleRow: true,
      showInFilterHeaderRow: false
    };
    var _isSelectAllChecked = false;

    var _options = $.extend(true, {}, _defaults, options);

    function init(grid) {
      _grid = grid;
      _handler
      .subscribe(_grid.onSelectedRowsChanged, handleSelectedRowsChanged)
      .subscribe(_grid.onClick, handleClick)
      .subscribe(_grid.onKeyDown, handleKeyDown);

      if (_options.showInFilterHeaderRow) {
        addCheckboxToFilterHeaderRow(grid);
      }
      if (_options.showInColumnTitleRow) {
        _handler.subscribe(_grid.onHeaderClick, handleHeaderClick)
      }
    }

    function destroy() {
      _handler.unsubscribeAll();
    }

    function getOptions() {
      return _options;
    }

    function setOptions(options) {
      _options = $.extend(true, {}, _options, options);

      if (_options.hideSelectAllCheckbox) {
        hideSelectAllFromColumnHeaderTitleRow();
        hideSelectAllFromColumnHeaderFilterRow();
      } else {
        if (_options.showInColumnTitleRow) {
          if (_isSelectAllChecked) {
            _grid.updateColumnHeader(_options.columnId, "<input id='header-selector" + _selectAll_UID + "' type='checkbox' checked='checked'>", _options.toolTip);
          } else {
            _grid.updateColumnHeader(_options.columnId, "<input id='header-selector" + _selectAll_UID + "' type='checkbox'>", _options.toolTip);
          }
          _handler.subscribe(_grid.onHeaderClick, handleHeaderClick);
        } else {
          hideSelectAllFromColumnHeaderTitleRow();
        }

        if (_options.showInFilterHeaderRow) {
          var selectAllContainer = $("#filter-checkbox-selectall-container");
          selectAllContainer.show();
          selectAllContainer.find('input[type="checkbox"]').prop("checked", _isSelectAllChecked);
        } else {
          hideSelectAllFromColumnHeaderFilterRow();
        }
      }
    }

    function hideSelectAllFromColumnHeaderTitleRow() {
      _grid.updateColumnHeader(_options.columnId, "", "");
    }

    function hideSelectAllFromColumnHeaderFilterRow() {
      $("#filter-checkbox-selectall-container").hide();
    }

    function handleSelectedRowsChanged(e, args) {
      var selectedRows = _grid.getSelectedRows();
      var lookup = {}, row, i;
      for (i = 0; i < selectedRows.length; i++) {
        row = selectedRows[i];
        lookup[row] = true;
        if (lookup[row] !== _selectedRowsLookup[row]) {
          _grid.invalidateRow(row);
          delete _selectedRowsLookup[row];
        }
      }
      for (i in _selectedRowsLookup) {
        _grid.invalidateRow(i);
      }
      _selectedRowsLookup = lookup;
      _grid.render();
      _isSelectAllChecked = selectedRows.length && selectedRows.length == _grid.getDataLength();

      if (_options.showInColumnTitleRow && !_options.hideSelectAllCheckbox) {
        if (_isSelectAllChecked) {
          _grid.updateColumnHeader(_options.columnId, "<input id='header-selector" + _selectAll_UID + "' type='checkbox' checked='checked'>", _options.toolTip);
        } else {
          _grid.updateColumnHeader(_options.columnId, "<input id='header-selector" + _selectAll_UID + "' type='checkbox'>", _options.toolTip);
        }
      }
      if (_options.showInFilterHeaderRow) {
        var selectAllElm = $("#header-filter-selector" + _selectAll_UID);
        selectAllElm.prop("checked", _isSelectAllChecked);
      }
    }

    function handleKeyDown(e, args) {
      if (e.which == 32) {
        if (_grid.getColumns()[args.cell].id === _options.columnId) {
          // if editing, try to commit
          if (!_grid.getEditorLock().isActive() || _grid.getEditorLock().commitCurrentEdit()) {
            toggleRowSelection(args.row);
          }
          e.preventDefault();
          e.stopImmediatePropagation();
        }
      }
    }

    function handleClick(e, args) {
      // clicking on a row select checkbox
      if (_grid.getColumns()[args.cell].id === _options.columnId && $(e.target).is(":checkbox")) {
        // if editing, try to commit
        if (_grid.getEditorLock().isActive() && !_grid.getEditorLock().commitCurrentEdit()) {
          e.preventDefault();
          e.stopImmediatePropagation();
          return;
        }

        toggleRowSelection(args.row);
        e.stopPropagation();
        e.stopImmediatePropagation();
      }
    }

    function toggleRowSelection(row) {
      if (_selectedRowsLookup[row]) {
        _grid.setSelectedRows($.grep(_grid.getSelectedRows(), function (n) {
          return n != row
        }));
      } else {
        _grid.setSelectedRows(_grid.getSelectedRows().concat(row));
      }
      _grid.setActiveCell(row, getCheckboxColumnCellIndex());
      _grid.focus();
    }

    function selectRows(rowArray) {
      var i, l=rowArray.length, addRows = [];
      for(i=0; i<l; i++) {
        if (!_selectedRowsLookup[rowArray[i]]) {
          addRows[addRows.length] = rowArray[i];
        }
      }
      _grid.setSelectedRows(_grid.getSelectedRows().concat(addRows));
    }

    function deSelectRows(rowArray) {
      var i, l=rowArray.length, removeRows = [];
      for(i=0; i<l; i++) {
        if (_selectedRowsLookup[rowArray[i]]) {
          removeRows[removeRows.length] = rowArray[i];
        }
      }
      _grid.setSelectedRows($.grep(_grid.getSelectedRows(), function (n) {
        return removeRows.indexOf(n)<0
      }));
    }

    function handleHeaderClick(e, args) {
      if (args.column.id == _options.columnId && $(e.target).is(":checkbox")) {
        // if editing, try to commit
        if (_grid.getEditorLock().isActive() && !_grid.getEditorLock().commitCurrentEdit()) {
          e.preventDefault();
          e.stopImmediatePropagation();
          return;
        }

        if ($(e.target).is(":checked")) {
          var rows = [];
          for (var i = 0; i < _grid.getDataLength(); i++) {
            rows.push(i);
          }
          _grid.setSelectedRows(rows);
        } else {
          _grid.setSelectedRows([]);
        }
        e.stopPropagation();
        e.stopImmediatePropagation();
      }
    }

    var _checkboxColumnCellIndex = null;

    function getCheckboxColumnCellIndex() {
      if (_checkboxColumnCellIndex === null) {
        _checkboxColumnCellIndex = 0;
        var colArr = _grid.getColumns();
        for (var i=0; i < colArr.length; i++) {
          if (colArr[i].id == _options.columnId) {
            _checkboxColumnCellIndex = i;
          }
        }
      }
      return _checkboxColumnCellIndex;
    }

    function getColumnDefinition() {
      return {
        id: _options.columnId,
        name: (_options.hideSelectAllCheckbox || !_options.showInColumnTitleRow) ? "" : "<input id='header-selector" + _selectAll_UID + "' type='checkbox'>",
        toolTip: _options.toolTip,
        field: "sel",
        width: _options.width,
        resizable: false,
        sortable: false,
        cssClass: _options.cssClass,
        hideSelectAllCheckbox: _options.hideSelectAllCheckbox,
        formatter: checkboxSelectionFormatter
      };
    }

    function addCheckboxToFilterHeaderRow(grid) {
      grid.onHeaderRowCellRendered.subscribe(function(e, args) {
        if (args.column.field === "sel") {
          $(args.node).empty();
          $("<input id='header-filter-selector" + _selectAll_UID + "' type='checkbox'>")
            .appendTo(args.node)
            .on('click', function(evnt) {
              handleHeaderClick(evnt, args)
            });
        }
      });
    }

    function createUID() {
      return Math.round(10000000 * Math.random());
    }

    function checkboxSelectionFormatter(row, cell, value, columnDef, dataContext) {
      var UID = createUID() + row;

      if (dataContext) {
        return _selectedRowsLookup[row]
            ? "<input id='selector" + UID + "' type='checkbox' checked='checked'>"
            : "<input id='selector" + UID + "' type='checkbox'>";
      }
      return null;
    }

    $.extend(this, {
      "init": init,
      "destroy": destroy,
      "deSelectRows": deSelectRows,
      "selectRows": selectRows,
      "getColumnDefinition": getColumnDefinition,
      "getOptions": getOptions,
      "setOptions": setOptions,
    });
  }
})(jQuery);<|endoftext|>


<commit_before>/** @babel */

import { Range, Point } from 'atom'

import { client } from '../connection'
const { searchdocs } = client.import({ rpc: ['searchdocs'] })

class DatatipProvider {
  providerName = "Julia-Client";
  grammarScopes = atom.config.get('julia-client.juliaSyntaxScopes');
  priority = 100;

  async datatip(editor, bufferPosition, mouseEvent) {
    // If the scope at `bufferPosition` is not valid code scope, do nothing
    const scopes = editor
      .scopeDescriptorForBufferPosition(bufferPosition)
      .getScopesArray();
    const nonCodeScope = scopes.find(scope => {
      return scope.search("comment") > -1 || scope.search("string") > -1;
    });
    if (nonCodeScope) return null;

    const { row, column } = bufferPosition;
    // const code = getRow(editor, row);
    // if (!code) return null;
    //
    // let cursorPositionStart = column;
    // let cursorPositionEnd = column;
    // const identifierEnd = code.slice(column).search(/\W/);
    // if (identifierEnd !== -1) cursorPositionEnd += identifierEnd;
    // cursorPositionStart = js_idx_to_char_idx(cursorPositionStart, code);
    // cursorPositionEnd = js_idx_to_char_idx(cursorPositionEnd, code);

    // client.boot()
    return new Promise((resolve, reject) => {
      // kernel.inspect(code, cursorPositionEnd, result => {
      //   const { data, found } = result;
      //   if (
      //     !found ||
      //     (!data["text/html"] && !data["text/markdown"] && !data["text/plain"])
      //   ) {
      //     reject(null);
      //   } else {
      //     resolve({
      //       range: new Range(
      //         new Point(row, cursorPositionStart),
      //         new Point(row, cursorPositionEnd)
      //       ),
      //       component: () => (
      //         <div
      //           className="hydrogen datatip"
      //           style={{
      //             fontSize:
      //               atom.config.get(`Hydrogen.outputAreaFontSize`) || "inherit"
      //           }}
      //         >
      //           <RichMedia data={data}>
      //             <Media.HTML />
      //             <Markdown />
      //             <Media.Plain />
      //           </RichMedia>
      //         </div>
      //       )
      //     });
      //   }
      // });
      resolve({
        range: new Range(
          new Point(row, column),
          new Point(row, column + 5)
        ),
        markedStrings: [{
          type: 'markdown',
          value: `I love **Julia**`
        }],
      });
    });
  }
}

export default new DatatipProvider();
<commit_msg>Setup code detection<commit_after>/** @babel */

import { Range, Point } from 'atom'

import { client } from '../connection'
import { modules } from '../runtime'
import { render } from './views'

const searchDoc = client.import('docs')
const { current } = modules
const wordRegex = /[^0-9A-Za-z_@]/

class DatatipProvider {
  providerName = "Julia-Client";
  grammarScopes = atom.config.get('julia-client.juliaSyntaxScopes');
  priority = 100;

  async datatip(editor, bufferPosition, mouseEvent) {
    // If Julia is not running, do nothing
    if (!client.isActive()) return null

    // If the scope at `bufferPosition` is not valid code scope, do nothing
    const scopes = editor
      .scopeDescriptorForBufferPosition(bufferPosition)
      .getScopesArray();
    const nonCodeScope = scopes.find(scope => {
      return scope.search("comment") > -1 || scope.search("string") > -1;
    });
    if (nonCodeScope) return null

    // Code to be inspected
    const { row, column } = bufferPosition
    const text = editor.lineTextForBufferRow(row)
    if (!text) return null
    let start = column
    const identifierStart = text.slice(0, column).split('').reverse().join('').search(wordRegex)
    if (identifierStart === -1) {
      start = 0
    } else {
      start -= identifierStart
    }
    let end = column
    const identifierEnd = text.slice(column).search(wordRegex)
    if (identifierEnd === -1) {
      end = text.length
    } else {
      end += identifierEnd
    }
    const word = text.slice(start, end)

    // Module
    const currentModule = current()
    const module = currentModule ? currentModule : 'Main'

    return new Promise((resolve, reject) => {
      searchDoc({ word: word, mod: module }).then((result) => {
        if (result.error) {
          reject(null)
        } else {
          resolve({
            range: new Range(
              new Point(row, start),
              new Point(row, end)
            ),
            markedStrings: [{
              type: 'markdown',
              value: `I love \`Julia\` !`
            }],
          });
        }
      })
    });
  }
}

export default new DatatipProvider();
<|endoftext|>


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

var util = require('util');
var utils = require('./util');
var http = require('http');
var EventEmitter = require('events').EventEmitter;
var Logger = require('../diagnostics/logger');

var DEFAULT_GLOBAL_CONCURRENCY = 5; //Default http connection limitation for nodejs
var globalConcurrency = DEFAULT_GLOBAL_CONCURRENCY;
http.globalAgent.maxSockets = Math.max(globalConcurrency, http.globalAgent.maxSockets);

/**
* Concurrent execute batch operation and call operation callback randomly or in sequence.
*/
function BatchOperation(name, options) {
  if (!options) {
    options = {};
  }

  this.name = name;
  this.logger = options.logger || new Logger(Logger.LogLevels.INFO);
  this.callbackInorder = options.callbackInorder === true;
  this._currentOperationId = this.callbackInorder ? 1 : -1;
  this._totalOperation = 0;
  this._activeOperation = 0;
  this._queuedOperation = 0;
  //finished operation should be removed from this array
  this._operations = [];
  this._emitter = null;
  this._enableComplete = false;
  this._ended = false;
  this._error = null;
  this._paused = false;
}

/**
* Operation state
*/
var OperationState = {
  INITED : 'inited',
  QUEUED : 'queued',
  RUNNING : 'running',
  COMPLETE : 'complete',
  CALLBACK : 'callback',
  ERROR : 'error'
};

BatchOperation.OperationState = OperationState;

/**
* Set batch operation concurrency
*/
BatchOperation.setConcurrency = function(concurrency) {
  if (concurrency) {
    globalConcurrency = concurrency;
    http.globalAgent.maxSockets = globalConcurrency;
  }
};

/**
* Is the workload heavy and reach the concurrency limitation
*/
BatchOperation.prototype.IsWorkloadHeavy = function() {
  //Only support one batch operation for now.
  //In order to work with the multiple batch operation, we can use global operation track objects
  //BatchOperation acquire a bunch of operation ids from global and allocated ids to RestOperation
  //RestOperation start to run in order of id
  return this._activeOperation >= globalConcurrency;
};

/**
* Add a operation into batch operation
*/
BatchOperation.prototype.addOperation = function(operation) {
  this._operations.push(operation);
  operation.status = OperationState.QUEUED;
  operation.operationId = this._getActiveOperationId();
  this._queuedOperation++;
  this.logger.debug(util.format('Add operation %d into batch operation %s.', operation.operationId, this.name));
  //Immediately start the idle operation if workload isn't heavy
  this._startIdleOperation();
  return this.IsWorkloadHeavy();
};

/**
* Enable batch operation complete when there is no operation to run.
*/
BatchOperation.prototype.enableComplete = function() {
  this._enableComplete = true;
  this.logger.debug(util.format('Enable batch operation %s complete', this.name));
  //Check idle operation
  this._startIdleOperation();
};

/**
* Stop firing user call back
*/
BatchOperation.prototype.pause = function() {
  this._paused = true;
};

/**
* Start firing user call back
*/
BatchOperation.prototype.resume = function() {
  if (this._paused) {
    this._paused = false;
    this._fireOperationUserCallback();
  }
};

/**
* Add event listener
*/
BatchOperation.prototype.on = function(event, listener) {
  if(!this._emitter) this._emitter = new EventEmitter();
  this._emitter.on(event, listener);
};

/**
* Select the idle operation in operation queues to run
*/
BatchOperation.prototype._startIdleOperation = function() {
  if (this.IsWorkloadHeavy()) {
    return;
  }

  if (this._queuedOperation === 0) {
    var ended = this._tryEmitEndEvent();
    if(ended) {
      return;
    }
  } else {
    var operation = null;
    this.logger.debug(util.format('Batch operation %s start idle operation', this.name));

    for(var i = 0, count = this._operations.length; i < count; i ++) {
      operation = this._operations[i];
      if(operation.status == OperationState.QUEUED) {
        this._runOperation(operation);
        if (this.IsWorkloadHeavy()) {
          break;
        }
      }
    }
  }

  if(!this._ended) {
    if (!this.IsWorkloadHeavy() && this._emitter) {
      this.logger.debug(util.format('Batch operation %s emit the drain event', this.name));
      this._emitter.emit('drain');
    }

    this.logger.debug(util.format('Start idle operation finished. Total:%d, Active:%d, Queued:%d',
      this._totalOperation, this._activeOperation, this._queuedOperation));
  }
};

/**
* Run operation
*/
BatchOperation.prototype._runOperation = function (operation) {
  this.logger.debug(util.format('Operation %d start to run', operation.operationId));
  var cb = this.getBatchOperationCallback(operation);
  operation.run(cb);
  this._activeOperation++;
  this._queuedOperation--;
};

/**
* Return an general operation call back.
* This callback is used to update the internal status and fire user's callback when operation is complete.
*/
BatchOperation.prototype.getBatchOperationCallback = function (operation) {
  var self = this;
  return function (error) {
    if (error) {
      self.logger.debug(util.format('Operation %d failed. Error %s', operation.operationId, error));
      //Abort the batch operation if one of them failed
      self.abort(error);
    } else {
      self.logger.debug(util.format('Operation %d succeed', operation.operationId));
    }
    operation._callbackArguments = arguments;
    if (self._paused) {
      operation.status = OperationState.CALLBACK;
      self.logger.debug(util.format('Batch operation pasued and Operation %d wait for firing callback', operation.operationId));
    } else if (self.callbackInorder) {
      if(self._currentOperationId === operation.operationId) {
        self._fireOperationUserCallback(operation);
      } else if (self._currentOperationId > operation.operationId) {
        throw new Error('Debug error: current callback operation id can\'t larger than oepration id');
      } else {
        operation.status = OperationState.CALLBACK;
        self.logger.debug(util.format('Operation %d wait for firing callback', operation.operationId));
      }
    } else {
      self._fireOperationUserCallback(operation);
    }

    operation = null;
    process.nextTick(function(){
      //A little bit trivial if there is no queued tasks
      self._startIdleOperation();
      self = null;
    });
  };
};

/**
* Abort all the operation
*/
BatchOperation.prototype.abort = function (abortError) {
  if (abortError) {
    //Can't really abort all operations now.
    this._error = abortError;
  }
};

/**
* Fire user's call back
*/
BatchOperation.prototype._fireOperationUserCallback = function (operation) {
  var index = -1;
  if (operation) {
    index = this._operations.indexOf(operation);
  } else if (this.callbackInorder) {
    index = this._getCurrentOperationIndex();
  }
  if(index != -1) {
    operation = this._operations[index];
    if(operation._userCallback) {
      this.logger.debug(util.format('Fire user call back for operation %d', operation.operationId));
      operation._fireUserCallback();
    }
    this._operations.splice(index, 1);
    this._activeOperation--;
    operation.status = OperationState.COMPLETE;
    index = operation = null;
    if(this._operations.length === 0) {
      //Emit end event with callbackInorder
      this._tryEmitEndEvent();
    }
    if(this.callbackInorder) {
      this._currentOperationId++;
    }
    if(!this._paused) {
      var self = this;
      process.nextTick(function(){
        //Download/upload are I/O-bound instead of Compute-bound tasks.
        //We can start async operations and fire user callback at the same time
        self._startIdleOperation();
        self._fireOperationUserCallback();
        self = null;
      });
    }
  }
};

/**
* Try to emit the BatchOperation end event
* End event means all the operation and callback already finished.
*/
BatchOperation.prototype._tryEmitEndEvent = function () {
  if(this._enableComplete && this._emitter && this._activeOperation === 0 && this._operations.length === 0) {
    if(!this._ended) {
      this._ended = true;
      this.logger.debug(util.format('Batch operation %s emit the end event', this.name));
      var retValue = null;
      this._emitter.emit('end', this._error, retValue);
      return true;
    }
  }
  return false;
};

/**
* Get the current active operation index.
* Only the active operation could call user's callback in sequence model.
* The other finished but not active operations should wait for wake up.
*/
BatchOperation.prototype._getCurrentOperationIndex = function () {
  var operation = null;
  for(var i = 0, len = this._operations.length; i < len; i++) {
    operation = this._operations[i];
    if (this.callbackInorder) {
      //Sequence mode
      if(operation.operationId == this._currentOperationId) {
        if (operation.status === OperationState.CALLBACK) {
          return i;
        } else if (operation.status === OperationState.COMPLETE) {
          this._currentOperationId ++;
          return this._getCurrentOperationIndex();
        } else {
          break;
        }
      }
    } else {
      //Random mode
      if (operation.status === OperationState.CALLBACK) {
        return i;
      }
    }
  }
  return -1;
};

/**
* Get an operation id
*/
BatchOperation.prototype._getActiveOperationId = function() {
  return ++this._totalOperation;
};

/**
* Rest operation in sdk
*/
function RestOperation(serviceClient, operation) {
  this.status = OperationState.Inited;
  this.operationId = -1;
  this._userCallback = arguments[arguments.length - 1];
  this._callbackArguments = null;
  var sliceEnd = arguments.length;
  if(utils.objectIsFunction(this._userCallback)) {
    sliceEnd--;
  } else {
    this._userCallback = null;
  }
  var operationArguments = Array.prototype.slice.call(arguments).slice(2, sliceEnd);
  sliceEnd = null;
  this.run = function(cb) {
    var func = serviceClient[operation];
    if(!func) {
      throw new Error(util.format('Unknown operation %s in serviceclient', operation));
    } else {
      if(!cb) cb = this._userCallback;
      operationArguments.push(cb);
      this.status = OperationState.RUNNING;
      func.apply(serviceClient, operationArguments);
      operationArguments = serviceClient = operation = null;
    }
  };

  this._fireUserCallback = function () {
    if(this._userCallback) {
      this._userCallback.apply(null, this._callbackArguments);
    }
    this._userCallback = this._callbackArguments = null;
  };
}

BatchOperation.RestOperation = RestOperation;

/**
* Common operation wrapper
*/
function CommonOperation(operationFunc, callback) {
  this.status = OperationState.Inited;
  this.operationId = -1;
  this._callbackArguments = null;
  var sliceStart = 2;
  if(utils.objectIsFunction(callback)) {
    this._userCallback = callback;
  } else {
    this._userCallback = null;
    sliceStart = 1;
  }
  var operationArguments = Array.prototype.slice.call(arguments).slice(sliceStart);
  this.run = function(cb) {
    if(!cb) cb = this._userCallback;
    operationArguments.push(cb);
    this.status = OperationState.RUNNING;
    operationFunc.apply(null, operationArguments);
    operationArguments = operationFunc = null;
  };

  this._fireUserCallback = function () {
    if(this._userCallback) {
      this._userCallback.apply(null, this._callbackArguments);
    }
    this._userCallback = this._callbackArguments = null;
  };
}

BatchOperation.CommonOperation = CommonOperation;

module.exports = BatchOperation;
<commit_msg>Enable queue operation and extend the concurrency capacity<commit_after>/**
* Copyright (c) Microsoft.  All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

var util = require('util');
var utils = require('./util');
var http = require('http');
var EventEmitter = require('events').EventEmitter;
var Logger = require('../diagnostics/logger');
var os = require('os');
var DEFAULT_OPERATION_MEMORY_USAGE = require('./constants').BlobConstants.DEFAULT_WRITE_BLOCK_SIZE_IN_BYTES;

var SystemTotalMemory = os.totalmem();
var DEFAULT_GLOBAL_CONCURRENCY = 5; //Default http connection limitation for nodejs
var globalConcurrency = DEFAULT_GLOBAL_CONCURRENCY;
http.globalAgent.maxSockets = Math.max(globalConcurrency, http.globalAgent.maxSockets);

/**
* Concurrent execute batch operation and call operation callback randomly or in sequence.
*/
function BatchOperation(name, options) {
  if (!options) {
    options = {};
  }

  this.name = name;
  this.logger = options.logger || new Logger(Logger.LogLevels.INFO);
  this.operationMemoryUsage = options.operationMemoryUsage || DEFAULT_OPERATION_MEMORY_USAGE;
  this.callbackInorder = options.callbackInorder === true;
  this._currentOperationId = this.callbackInorder ? 1 : -1;
  //Total operations count(queued and active and connected)
  this._totalOperation = 0;
  //Action operations count(The operations which are connecting to remote or executing callback)
  this._activeOperation = 0;
  //Queued operations count(The operations which are waiting for connecting to remote)
  this._queuedOperation = 0;
  //Connected operations count(The operations which are connecting to remote)
  this._connectedOperation = 0;
  //finished operation should be removed from this array
  this._operations = [];
  this._emitter = null;
  this._enableComplete = false;
  this._ended = false;
  this._error = null;
  this._paused = false;
}

/**
* Operation state
*/
var OperationState = {
  INITED : 'inited',
  QUEUED : 'queued',
  RUNNING : 'running',
  COMPLETE : 'complete',
  CALLBACK : 'callback',
  ERROR : 'error'
};

BatchOperation.OperationState = OperationState;

/**
* Set batch operation concurrency
*/
BatchOperation.setConcurrency = function(concurrency) {
  if (concurrency) {
    globalConcurrency = concurrency;
    http.globalAgent.maxSockets = globalConcurrency;
  }
};

/**
* Is the workload heavy and It can used to determine whether we could queue operations
*/
BatchOperation.prototype.IsWorkloadHeavy = function() {
  //Only support one batch operation for now.
  //In order to work with the multiple batch operation, we can use global operation track objects
  //BatchOperation acquire a bunch of operation ids from global and allocated ids to RestOperation
  //RestOperation start to run in order of id
  return this._activeOperation >= 5 * globalConcurrency ||
    (this._activeOperation >= globalConcurrency && this._getApproximateMemoryUsage() > 0.5 * SystemTotalMemory);
};

/**
* get the approximate memory usage for batch operation
*/
BatchOperation.prototype._getApproximateMemoryUsage = function() {
  var currentUsage = process.memoryUsage().rss;
  var futureUsage = (this._queuedOperation + this._connectedOperation) * this.operationMemoryUsage;
  return currentUsage + futureUsage;
};

/**
* Add a operation into batch operation
*/
BatchOperation.prototype.addOperation = function(operation) {
  this._operations.push(operation);
  operation.status = OperationState.QUEUED;
  operation.operationId = this._getActiveOperationId();
  this._queuedOperation++;
  this.logger.debug(util.format('Add operation %d into batch operation %s.', operation.operationId, this.name));
  //Immediately start the idle operation if workload isn't heavy
  this._startIdleOperation();
  return this.IsWorkloadHeavy();
};

/**
* Enable batch operation complete when there is no operation to run.
*/
BatchOperation.prototype.enableComplete = function() {
  this._enableComplete = true;
  this.logger.debug(util.format('Enable batch operation %s complete', this.name));
  //Check idle operation
  this._startIdleOperation();
};

/**
* Stop firing user call back
*/
BatchOperation.prototype.pause = function() {
  this._paused = true;
};

/**
* Start firing user call back
*/
BatchOperation.prototype.resume = function() {
  if (this._paused) {
    this._paused = false;
    this._fireOperationUserCallback();
  }
};

/**
* Add event listener
*/
BatchOperation.prototype.on = function(event, listener) {
  if(!this._emitter) this._emitter = new EventEmitter();
  this._emitter.on(event, listener);
};

/**
* Select the idle operation in operation queues to run
*/
BatchOperation.prototype._startIdleOperation = function() {
  if (this._queuedOperation === 0) {
    var ended = this._tryEmitEndEvent();
    if(ended) {
      return;
    }
  } else if(!this._isFullConnection()){
    var operation = null;
    this.logger.debug(util.format('Batch operation %s start idle operation', this.name));

    for(var i = 0, count = this._operations.length; i < count; i ++) {
      operation = this._operations[i];
      if(operation.status == OperationState.QUEUED) {
        this._runOperation(operation);
        if (this._isFullConnection()) {
          break;
        }
      }
    }
  }

  if(!this._ended) {
    if (!this.IsWorkloadHeavy() && this._emitter) {
      this.logger.debug(util.format('Batch operation %s emit the drain event', this.name));
      this._emitter.emit('drain');
    }

    this.logger.debug(util.format('Start idle operation finished. Total:%d, Active:%d, Connected: %d, Queued:%d',
      this._totalOperation, this._activeOperation, this._connectedOperation, this._queuedOperation));
  }
};

/**
* Is the concurrent connection full
*/
BatchOperation.prototype._isFullConnection = function () {
  return this._connectedOperation >= globalConcurrency;
};

/**
* Run operation
*/
BatchOperation.prototype._runOperation = function (operation) {
  this.logger.debug(util.format('Operation %d start to run', operation.operationId));
  var cb = this.getBatchOperationCallback(operation);
  operation.run(cb);
  this._activeOperation++;
  this._queuedOperation--;
  this._connectedOperation++;
};

/**
* Release one connection and immediately start another connection if workload is not heavy
*/
BatchOperation.prototype._releaseConnection = function() {
  this._connectedOperation--;
  this._startIdleOperation();
};

/**
* Return an general operation call back.
* This callback is used to update the internal status and fire user's callback when operation is complete.
*/
BatchOperation.prototype.getBatchOperationCallback = function (operation) {
  var self = this;
  return function (error) {
    self._releaseConnection();
    if (error) {
      self.logger.debug(util.format('Operation %d failed. Error %s', operation.operationId, error));
      //Abort the batch operation if one of them failed
      self.abort(error);
    } else {
      self.logger.debug(util.format('Operation %d succeed', operation.operationId));
    }
    operation._callbackArguments = arguments;
    if (self._paused) {
      operation.status = OperationState.CALLBACK;
      self.logger.debug(util.format('Batch operation pasued and Operation %d wait for firing callback', operation.operationId));
    } else if (self.callbackInorder) {
      if(self._currentOperationId === operation.operationId) {
        self._fireOperationUserCallback(operation);
      } else if (self._currentOperationId > operation.operationId) {
        throw new Error('Debug error: current callback operation id can\'t larger than oepration id');
      } else {
        operation.status = OperationState.CALLBACK;
        self.logger.debug(util.format('Operation %d wait for firing callback', operation.operationId));
      }
    } else {
      self._fireOperationUserCallback(operation);
    }

    operation = null;
    self = null;
  };
};

/**
* Abort all the operation
*/
BatchOperation.prototype.abort = function (abortError) {
  if (abortError) {
    //Can't really abort all operations now.
    this._error = abortError;
  }
};

/**
* Fire user's call back
*/
BatchOperation.prototype._fireOperationUserCallback = function (operation) {
  var index = -1;
  if (operation) {
    index = this._operations.indexOf(operation);
  } else if (this.callbackInorder) {
    index = this._getCurrentOperationIndex();
  }
  if(index != -1) {
    operation = this._operations[index];
    if(operation._userCallback) {
      this.logger.debug(util.format('Fire user call back for operation %d', operation.operationId));
      operation._fireUserCallback();
    }
    this._operations.splice(index, 1);
    this._activeOperation--;
    operation.status = OperationState.COMPLETE;
    index = operation = null;
    if(this._operations.length === 0) {
      //Emit end event with callbackInorder
      this._tryEmitEndEvent();
    }
    if(this.callbackInorder) {
      this._currentOperationId++;
    }
    if(!this._paused) {
      var self = this;
      process.nextTick(function(){
        //Download/upload are I/O-bound instead of Compute-bound tasks.
        //We can start async operations and fire user callback at the same time
        self._startIdleOperation();
        self._fireOperationUserCallback();
        self = null;
      });
    }
  }
};

/**
* Try to emit the BatchOperation end event
* End event means all the operation and callback already finished.
*/
BatchOperation.prototype._tryEmitEndEvent = function () {
  if(this._enableComplete && this._emitter && this._activeOperation === 0 && this._operations.length === 0) {
    if(!this._ended) {
      this._ended = true;
      this.logger.debug(util.format('Batch operation %s emit the end event', this.name));
      var retValue = null;
      this._emitter.emit('end', this._error, retValue);
      return true;
    }
  }
  return false;
};

/**
* Get the current active operation index.
* Only the active operation could call user's callback in sequence model.
* The other finished but not active operations should wait for wake up.
*/
BatchOperation.prototype._getCurrentOperationIndex = function () {
  var operation = null;
  for(var i = 0, len = this._operations.length; i < len; i++) {
    operation = this._operations[i];
    if (this.callbackInorder) {
      //Sequence mode
      if(operation.operationId == this._currentOperationId) {
        if (operation.status === OperationState.CALLBACK) {
          return i;
        } else if (operation.status === OperationState.COMPLETE) {
          this._currentOperationId ++;
          return this._getCurrentOperationIndex();
        } else {
          break;
        }
      }
    } else {
      //Random mode
      if (operation.status === OperationState.CALLBACK) {
        return i;
      }
    }
  }
  return -1;
};

/**
* Get an operation id
*/
BatchOperation.prototype._getActiveOperationId = function() {
  return ++this._totalOperation;
};

/**
* Rest operation in sdk
*/
function RestOperation(serviceClient, operation) {
  this.status = OperationState.Inited;
  this.operationId = -1;
  this._userCallback = arguments[arguments.length - 1];
  this._callbackArguments = null;
  var sliceEnd = arguments.length;
  if(utils.objectIsFunction(this._userCallback)) {
    sliceEnd--;
  } else {
    this._userCallback = null;
  }
  var operationArguments = Array.prototype.slice.call(arguments).slice(2, sliceEnd);
  sliceEnd = null;
  this.run = function(cb) {
    var func = serviceClient[operation];
    if(!func) {
      throw new Error(util.format('Unknown operation %s in serviceclient', operation));
    } else {
      if(!cb) cb = this._userCallback;
      operationArguments.push(cb);
      this.status = OperationState.RUNNING;
      func.apply(serviceClient, operationArguments);
      operationArguments = serviceClient = operation = null;
    }
  };

  this._fireUserCallback = function () {
    if(this._userCallback) {
      this._userCallback.apply(null, this._callbackArguments);
    }
    this._userCallback = this._callbackArguments = null;
  };
}

BatchOperation.RestOperation = RestOperation;

/**
* Common operation wrapper
*/
function CommonOperation(operationFunc, callback) {
  this.status = OperationState.Inited;
  this.operationId = -1;
  this._callbackArguments = null;
  var sliceStart = 2;
  if(utils.objectIsFunction(callback)) {
    this._userCallback = callback;
  } else {
    this._userCallback = null;
    sliceStart = 1;
  }
  var operationArguments = Array.prototype.slice.call(arguments).slice(sliceStart);
  this.run = function(cb) {
    if(!cb) cb = this._userCallback;
    operationArguments.push(cb);
    this.status = OperationState.RUNNING;
    operationFunc.apply(null, operationArguments);
    operationArguments = operationFunc = null;
  };

  this._fireUserCallback = function () {
    if(this._userCallback) {
      this._userCallback.apply(null, this._callbackArguments);
    }
    this._userCallback = this._callbackArguments = null;
  };
}

BatchOperation.CommonOperation = CommonOperation;

module.exports = BatchOperation;
<|endoftext|>


<commit_before>'use strict';
import SwaggerParser from 'swagger-parser';
import JsonPointer from './JsonPointer';
import {methods as swaggerMethods} from  './swagger-defs';

export default class SchemaManager {
  constructor() {
    if (SchemaManager.prototype._instance) {
      return SchemaManager.prototype._instance;
    }

    SchemaManager.prototype._instance = this;

    this._schema = {};
  }

  static instance() {
    return new SchemaManager();
  }

  load(url) {
    let promise = new Promise((resolve, reject) => {
      this._schema = {};

      SwaggerParser.bundle(url, {http: {withCredentials: false}})
        .then(
          (schema) => {
            this._schema = schema;
            resolve(this._schema);
          },
          (err) => reject(err)
        );
    });

    return promise;
  }

  get schema() {
    // TODO: consider returning promise
    return this._schema;
  }

  byPointer(pointer) {
    let res = null;
    try {
      res = JsonPointer.get(this._schema, pointer);
    } catch(e)  {/*skip*/ }
    return res;
  }

  resolveRefs(obj) {
    Object.keys(obj).forEach(key => {
      if (obj[key].$ref) {
        obj[key] = this.byPointer(obj[key].$ref);
      }
    });
    return obj;
  }

  getMethodParams(methodPtr, resolveRefs) {
    /* inject JsonPointer into array elements */
    function injectPointers(array, root) {
      if (!array) return array;
      return array.map((element, idx) => {
        element._pointer = JsonPointer.join(root, idx);
        return element;
      });
    }

    //get path params
    let ptr = JsonPointer.dirName(methodPtr, 2) + '/parameters';
    let pathParams = this.byPointer(ptr);
    if (Array.isArray(pathParams)) {
      pathParams = injectPointers(pathParams, ptr);
    } else if (pathParams && pathParams.$ref) {
      pathParams = injectPointers(this.byPointer(pathParams.$ref), pathParams.$ref);
    } else {
      pathParams = [];
    }

    let methodParams = injectPointers(this.byPointer(methodPtr), methodPtr) || [];
    if (resolveRefs) {
      methodParams = this.resolveRefs(methodParams);
    }
    return methodParams.concat(pathParams);
  }

  /* returns ES6 Map */
  buildMenuTree() {
    let tag2MethodMapping = new Map();

    let definedTags = this._schema.tags || [];
    // add tags into map to preserve order
    for (let tag of definedTags) {
      tag2MethodMapping.set(tag.name, {
        'description': tag.description,
        'x-secondaryTag': tag['x-secondaryTag'],
        'methods': []
      });
    }

    let paths = this._schema.paths;
    for (let path of Object.keys(paths)) {
      let methods = Object.keys(paths[path]).filter((k) => swaggerMethods.has(k));
      for (let method of methods) {
        let methodInfo = paths[path][method];
        let tags = methodInfo.tags;

        //TODO: mb need to do something cleverer
        if (!tags || !tags.length) {
          tags = ['[Other]'];
        }
        let methodPointer = JsonPointer.compile(['paths', path, method]);
        let methodSummary = methodInfo.summary;
        for (let tag of tags) {
          let tagDetails = tag2MethodMapping.get(tag);
          if (!tagDetails) {
            tagDetails = {};
            tag2MethodMapping.set(tag, tagDetails);
          }
          if (tagDetails['x-secondaryTag']) continue;
          if (!tagDetails.methods) tagDetails.methods = [];
          tagDetails.methods.push({pointer: methodPointer, summary: methodSummary});
        }
      }
    }
    return tag2MethodMapping;
  }

}
<commit_msg>Add path params resolving<commit_after>'use strict';
import SwaggerParser from 'swagger-parser';
import JsonPointer from './JsonPointer';
import {methods as swaggerMethods} from  './swagger-defs';

export default class SchemaManager {
  constructor() {
    if (SchemaManager.prototype._instance) {
      return SchemaManager.prototype._instance;
    }

    SchemaManager.prototype._instance = this;

    this._schema = {};
  }

  static instance() {
    return new SchemaManager();
  }

  load(url) {
    let promise = new Promise((resolve, reject) => {
      this._schema = {};

      SwaggerParser.bundle(url, {http: {withCredentials: false}})
        .then(
          (schema) => {
            this._schema = schema;
            resolve(this._schema);
          },
          (err) => reject(err)
        );
    });

    return promise;
  }

  get schema() {
    // TODO: consider returning promise
    return this._schema;
  }

  byPointer(pointer) {
    let res = null;
    try {
      res = JsonPointer.get(this._schema, pointer);
    } catch(e)  {/*skip*/ }
    return res;
  }

  resolveRefs(obj) {
    Object.keys(obj).forEach(key => {
      if (obj[key].$ref) {
        obj[key] = this.byPointer(obj[key].$ref);
      }
    });
    return obj;
  }

  getMethodParams(methodPtr, resolveRefs) {
    /* inject JsonPointer into array elements */
    function injectPointers(array, root) {
      if (!array) return array;
      return array.map((element, idx) => {
        element._pointer = JsonPointer.join(root, idx);
        return element;
      });
    }

    //get path params
    let ptr = JsonPointer.dirName(methodPtr, 2) + '/parameters';
    let pathParams = this.byPointer(ptr);
    if (Array.isArray(pathParams)) {
      pathParams = injectPointers(pathParams, ptr);
    } else if (pathParams && pathParams.$ref) {
      pathParams = injectPointers(this.byPointer(pathParams.$ref), pathParams.$ref);
    } else {
      pathParams = [];
    }

    let methodParams = injectPointers(this.byPointer(methodPtr), methodPtr) || [];
    if (resolveRefs) {
      methodParams = this.resolveRefs(methodParams);
      pathParams = this.resolveRefs(pathParams);
    }
    return methodParams.concat(pathParams);
  }

  /* returns ES6 Map */
  buildMenuTree() {
    let tag2MethodMapping = new Map();

    let definedTags = this._schema.tags || [];
    // add tags into map to preserve order
    for (let tag of definedTags) {
      tag2MethodMapping.set(tag.name, {
        'description': tag.description,
        'x-secondaryTag': tag['x-secondaryTag'],
        'methods': []
      });
    }

    let paths = this._schema.paths;
    for (let path of Object.keys(paths)) {
      let methods = Object.keys(paths[path]).filter((k) => swaggerMethods.has(k));
      for (let method of methods) {
        let methodInfo = paths[path][method];
        let tags = methodInfo.tags;

        //TODO: mb need to do something cleverer
        if (!tags || !tags.length) {
          tags = ['[Other]'];
        }
        let methodPointer = JsonPointer.compile(['paths', path, method]);
        let methodSummary = methodInfo.summary;
        for (let tag of tags) {
          let tagDetails = tag2MethodMapping.get(tag);
          if (!tagDetails) {
            tagDetails = {};
            tag2MethodMapping.set(tag, tagDetails);
          }
          if (tagDetails['x-secondaryTag']) continue;
          if (!tagDetails.methods) tagDetails.methods = [];
          tagDetails.methods.push({pointer: methodPointer, summary: methodSummary});
        }
      }
    }
    return tag2MethodMapping;
  }

}
<|endoftext|>