<commit_before>var _ = require('underscore'),
    urlTools = require('../util/urlTools'),
    vm = require('vm'),
    uglifyJs = require('uglify-js-papandreou'),
    uglifyAst = require('uglifyast');

module.exports = function (queryObj) {
    return function bundleRequireJs(assetGraph) {
        var requireJsConfig = assetGraph.requireJsConfig,
            assetsToCleanUp = [];
        if (!requireJsConfig) {
            throw new Error('transforms.bundleRequireJs: No assetGraph.requireJsConfig found, please run transforms.registerRequireJsConfig first');
        }
        assetGraph.findAssets(_.extend({type: 'Html'}, queryObj)).forEach(function (htmlAsset) {
            var existingHtmlStyleRelations = assetGraph.findRelations({type: 'HtmlStyle', from: htmlAsset}, true), // includeUnpopulated
                seenKnockoutJsTemplateNames = {},
                htmlStyleInsertionPoint;
            if (existingHtmlStyleRelations.length > 0) {
                htmlStyleInsertionPoint = existingHtmlStyleRelations[existingHtmlStyleRelations.length - 1];
            }

            assetGraph.findRelations({from: htmlAsset, type: ['HtmlRequireJsMain', 'HtmlScript']}).forEach(function (startRelation) {

                // Don't do anything for regular scripts that don't use require:
                if (startRelation.type === 'HtmlScript' && assetGraph.findRelations({from: startRelation.to, type: 'JavaScriptAmdRequire'}).length === 0) {
                    return;
                }

                var fallbackBaseUrl = (startRelation.to.url || htmlAsset.url).replace(/[^\/]+$/, ''),
                    outgoingRelations = [],
                    assetsToBundle = [],
                    bundleTopLevelStatements = [];

                function getModuleName(asset) {
                    return requireJsConfig.getModuleName(asset, fallbackBaseUrl);
                }

                assetGraph.eachAssetPostOrder(startRelation, {type: ['JavaScriptAmdRequire', 'JavaScriptAmdDefine', 'JavaScriptShimRequire'], to: {type: 'JavaScript'}}, function (asset) {
                    var clonedAsset = asset.clone();
                    assetsToCleanUp.push(asset);
                    assetsToBundle.push(clonedAsset);
                    assetGraph.findRelations({from: clonedAsset}, true).forEach(function (outgoingRelation) {
                        var injectDefineStatementValueAst;
                        if (/^JavaScript(?:ShimRequire|Amd(?:Define|Require))$/.test(outgoingRelation.type)) {
                            if (outgoingRelation.to.type === 'JavaScript') {
                                var targetModuleName = getModuleName(outgoingRelation.to);
                                if (outgoingRelation.to._notAmd && targetModuleName !== 'jquery' && // require-jquery.js special cases 'jquery'
                                    (!requireJsConfig.shim[targetModuleName] || !requireJsConfig.shim[targetModuleName].exports)) {

                                    outgoingRelation.detach();
                                } else {
                                    assetGraph.removeRelation(outgoingRelation);
                                }
                            } else if (outgoingRelation.to.type === 'Css' || outgoingRelation.to.type === 'Less') {
                                var newHtmlStyle = new assetGraph.constructor.relations.HtmlStyle({to: outgoingRelation.to});
                                if (htmlStyleInsertionPoint) {
                                    newHtmlStyle.attach(htmlAsset, 'after', htmlStyleInsertionPoint);
                                } else {
                                    newHtmlStyle.attach(htmlAsset, 'first');
                                }
                                htmlStyleInsertionPoint = newHtmlStyle;
                                outgoingRelation.detach();
                            } else if (outgoingRelation.to.isText) {
                                injectDefineStatementValueAst = ['call', ['name', 'GETTEXT'], [['string', '<urlGoesHere>']]];
                                var oneGetTextRelation = new assetGraph.constructor.relations.JavaScriptGetText({
                                    node: injectDefineStatementValueAst,
                                    from: clonedAsset,
                                    to: outgoingRelation.to
                                });
                                outgoingRelations.push(oneGetTextRelation);

                                if (outgoingRelation.to.type === 'KnockoutJsTemplate') {
                                    var templateName = getModuleName(outgoingRelation.to).replace(/^.*\/|\.ko$/g, '');
                                    if (Object.prototype.hasOwnProperty.call(seenKnockoutJsTemplateNames, templateName)) {
                                        assetGraph.emit('error', new Error('bundleRequireJs: More than one of the loaded Knockout.js templates have the file name ' + templateName + '.ko, so they will overwrite each other in the ko.externalTemplateEngine.templates hash. Please disambiguate by changing at least one of the file names.'));
                                    } else {
                                        seenKnockoutJsTemplateNames[templateName] = true;
                                    }
                                    injectDefineStatementValueAst = ['assign', true, ['sub', ['dot', ['dot', ['name', 'ko'], 'externalTemplateEngine'], 'templates'], ['string', templateName]], injectDefineStatementValueAst];
                                    outgoingRelation.node[1] = outgoingRelation.node[1].replace(/^tpl!/, '');
                                } else {
                                    outgoingRelation.node[1] = outgoingRelation.node[1].replace(/^text!/, "");
                                }
                            } else {
                                assetGraph.emit('warn', new Error("bundleRequireJs: Skipping unsupported outgoing relation: " + outgoingRelation.toString()));
                            }
                            if (injectDefineStatementValueAst) {
                                bundleTopLevelStatements.push(['stat', ['call', ['name', 'define'], [['string', getModuleName(outgoingRelation.to)], injectDefineStatementValueAst]]]);
                            }
                        } else {
                            outgoingRelations.push(outgoingRelation);
                        }
                    });

                    // Check for existing define() statements:
                    var hasFoundPlausibleDefineStatementValueAst = false,
                        topLevelStatements = clonedAsset.parseTree[1],
                        injectDefineStatementValueAst;

                    if (topLevelStatements.length === 1 && topLevelStatements[0][0] === 'stat' &&
                        topLevelStatements[0][1][0] === 'call' &&
                        topLevelStatements[0][1][1][0] === 'function' &&
                        topLevelStatements[0][1][1][3].length === 1 &&
                        topLevelStatements[0][1][1][3][0][0] === 'if') {

                        var numDefineStatements = 0,
                            walker = uglifyJs.uglify.ast_walker();
                        walker.with_walkers({
                            call: function (expr, args) {
                                if (expr[0] === 'name' && expr[1] === 'define') {
                                    numDefineStatements += 1;
                                }
                            }
                        }, function () {
                            walker.walk(topLevelStatements[0][1][1]);
                        });
                        if (numDefineStatements === 1) {
                            var context = vm.createContext(),
                                factory;
                            context.define = function () {
                                if (arguments.length > 0 && typeof arguments[arguments.length - 1] === 'function') {
                                    factory = arguments[arguments.length - 1];
                                }
                            };
                            context.define.amd = {jQuery: true, multiversion: true, plugins: true};

                            try {
                                vm.runInContext(uglifyJs.uglify.gen_code(topLevelStatements[0]), context);
                            } catch (e) {
                                factory = false;
                            }
                            if (factory) {
                                injectDefineStatementValueAst = uglifyAst.objToAst(factory);
                                topLevelStatements = clonedAsset.parseTree[1] = [];
                                hasFoundPlausibleDefineStatementValueAst = true;
                            }
                        }
                    }
                    if (!hasFoundPlausibleDefineStatementValueAst) {
                        var callDefineAsts = [],
                            walker = uglifyJs.uglify.ast_walker();
                        walker.with_walkers({
                            call: function (expr) {
                                if (expr[0] === 'name' && expr[1] === 'define') {
                                    var stack = walker.stack();
                                    callDefineAsts.push(stack[stack.length - 1]);
                                }
                            }
                        }, function () {
                            walker.walk(clonedAsset.parseTree);
                        });
                        if (callDefineAsts.length === 1) {
                            var moduleName = getModuleName(asset);
                            if (moduleName) {
                                if (asset === startRelation.to) {
                                    // Strip "scripts/" prefix of the main module (hmm, not sure?)
                                    moduleName = moduleName.replace(/^.*\//, "");
                                }
                                var firstArgumentIsString = callDefineAsts[0][2].length > 0 && callDefineAsts[0][2][0][0] === 'string';
                                callDefineAsts[0][2].splice(0, firstArgumentIsString ? 1 : 0, ['string', moduleName]);
                            }
                            injectDefineStatementValueAst = null;
                            hasFoundPlausibleDefineStatementValueAst = true;
                        }
                    }
                    if (injectDefineStatementValueAst) {
                        bundleTopLevelStatements.push(['stat', ['call', ['name', 'define'], [['string', getModuleName(asset)], injectDefineStatementValueAst]]]);
                    }
                    if (!hasFoundPlausibleDefineStatementValueAst) {
                        asset._notAmd = true;
                    }
                    Array.prototype.push.apply(bundleTopLevelStatements, clonedAsset.parseTree[1]);
                });
                startRelation.to.replaceWith(new assetGraph.constructor.assets.JavaScript({
                    url: startRelation.to.url,
                    parseTree: ['toplevel', bundleTopLevelStatements],
                    outgoingRelations: outgoingRelations
                }));
                outgoingRelations.forEach(function (outgoingRelation) {
                    outgoingRelation.refreshHref();
                });
                assetsToBundle.forEach(function (asset) {
                    assetGraph.removeAsset(asset);
                });
            });
        });
        assetsToCleanUp.forEach(function (asset) {
            if (asset.assetGraph && asset.incomingRelations.every(function (incomingRelation) {return assetsToCleanUp.indexOf(incomingRelation.from) !== -1;})) {
                assetGraph.removeAsset(asset);
            }
        });
        assetGraph.recomputeBaseAssets(true);
    };
};
<commit_msg>transforms.bundleRequireJs: Strip locale id from module name when extracting the template name from the AMD module name.<commit_after>var _ = require('underscore'),
    urlTools = require('../util/urlTools'),
    vm = require('vm'),
    uglifyJs = require('uglify-js-papandreou'),
    uglifyAst = require('uglifyast');

module.exports = function (queryObj) {
    return function bundleRequireJs(assetGraph) {
        var requireJsConfig = assetGraph.requireJsConfig,
            assetsToCleanUp = [];
        if (!requireJsConfig) {
            throw new Error('transforms.bundleRequireJs: No assetGraph.requireJsConfig found, please run transforms.registerRequireJsConfig first');
        }
        assetGraph.findAssets(_.extend({type: 'Html'}, queryObj)).forEach(function (htmlAsset) {
            var existingHtmlStyleRelations = assetGraph.findRelations({type: 'HtmlStyle', from: htmlAsset}, true), // includeUnpopulated
                seenKnockoutJsTemplateNames = {},
                htmlStyleInsertionPoint;
            if (existingHtmlStyleRelations.length > 0) {
                htmlStyleInsertionPoint = existingHtmlStyleRelations[existingHtmlStyleRelations.length - 1];
            }

            assetGraph.findRelations({from: htmlAsset, type: ['HtmlRequireJsMain', 'HtmlScript']}).forEach(function (startRelation) {

                // Don't do anything for regular scripts that don't use require:
                if (startRelation.type === 'HtmlScript' && assetGraph.findRelations({from: startRelation.to, type: 'JavaScriptAmdRequire'}).length === 0) {
                    return;
                }

                var fallbackBaseUrl = (startRelation.to.url || htmlAsset.url).replace(/[^\/]+$/, ''),
                    outgoingRelations = [],
                    assetsToBundle = [],
                    bundleTopLevelStatements = [];

                function getModuleName(asset) {
                    return requireJsConfig.getModuleName(asset, fallbackBaseUrl);
                }

                assetGraph.eachAssetPostOrder(startRelation, {type: ['JavaScriptAmdRequire', 'JavaScriptAmdDefine', 'JavaScriptShimRequire'], to: {type: 'JavaScript'}}, function (asset) {
                    var clonedAsset = asset.clone();
                    assetsToCleanUp.push(asset);
                    assetsToBundle.push(clonedAsset);
                    assetGraph.findRelations({from: clonedAsset}, true).forEach(function (outgoingRelation) {
                        var injectDefineStatementValueAst;
                        if (/^JavaScript(?:ShimRequire|Amd(?:Define|Require))$/.test(outgoingRelation.type)) {
                            if (outgoingRelation.to.type === 'JavaScript') {
                                var targetModuleName = getModuleName(outgoingRelation.to);
                                if (outgoingRelation.to._notAmd && targetModuleName !== 'jquery' && // require-jquery.js special cases 'jquery'
                                    (!requireJsConfig.shim[targetModuleName] || !requireJsConfig.shim[targetModuleName].exports)) {

                                    outgoingRelation.detach();
                                } else {
                                    assetGraph.removeRelation(outgoingRelation);
                                }
                            } else if (outgoingRelation.to.type === 'Css' || outgoingRelation.to.type === 'Less') {
                                var newHtmlStyle = new assetGraph.constructor.relations.HtmlStyle({to: outgoingRelation.to});
                                if (htmlStyleInsertionPoint) {
                                    newHtmlStyle.attach(htmlAsset, 'after', htmlStyleInsertionPoint);
                                } else {
                                    newHtmlStyle.attach(htmlAsset, 'first');
                                }
                                htmlStyleInsertionPoint = newHtmlStyle;
                                outgoingRelation.detach();
                            } else if (outgoingRelation.to.isText) {
                                injectDefineStatementValueAst = ['call', ['name', 'GETTEXT'], [['string', '<urlGoesHere>']]];
                                var oneGetTextRelation = new assetGraph.constructor.relations.JavaScriptGetText({
                                    node: injectDefineStatementValueAst,
                                    from: clonedAsset,
                                    to: outgoingRelation.to
                                });
                                outgoingRelations.push(oneGetTextRelation);

                                if (outgoingRelation.to.type === 'KnockoutJsTemplate') {
                                    var templateName = getModuleName(outgoingRelation.to).replace(/^.*\/|(?:\.\w+)?\.ko$/g, ''); // Strip path, locale id suffix and .ko extension
                                    if (Object.prototype.hasOwnProperty.call(seenKnockoutJsTemplateNames, templateName)) {
                                        assetGraph.emit('error', new Error('bundleRequireJs: More than one of the loaded Knockout.js templates have the file name ' + templateName + '.ko, so they will overwrite each other in the ko.externalTemplateEngine.templates hash. Please disambiguate by changing at least one of the file names.'));
                                    } else {
                                        seenKnockoutJsTemplateNames[templateName] = true;
                                    }
                                    injectDefineStatementValueAst = ['assign', true, ['sub', ['dot', ['dot', ['name', 'ko'], 'externalTemplateEngine'], 'templates'], ['string', templateName]], injectDefineStatementValueAst];
                                    outgoingRelation.node[1] = outgoingRelation.node[1].replace(/^tpl!/, '');
                                } else {
                                    outgoingRelation.node[1] = outgoingRelation.node[1].replace(/^text!/, "");
                                }
                            } else {
                                assetGraph.emit('warn', new Error("bundleRequireJs: Skipping unsupported outgoing relation: " + outgoingRelation.toString()));
                            }
                            if (injectDefineStatementValueAst) {
                                bundleTopLevelStatements.push(['stat', ['call', ['name', 'define'], [['string', getModuleName(outgoingRelation.to)], injectDefineStatementValueAst]]]);
                            }
                        } else {
                            outgoingRelations.push(outgoingRelation);
                        }
                    });

                    // Check for existing define() statements:
                    var hasFoundPlausibleDefineStatementValueAst = false,
                        topLevelStatements = clonedAsset.parseTree[1],
                        injectDefineStatementValueAst;

                    if (topLevelStatements.length === 1 && topLevelStatements[0][0] === 'stat' &&
                        topLevelStatements[0][1][0] === 'call' &&
                        topLevelStatements[0][1][1][0] === 'function' &&
                        topLevelStatements[0][1][1][3].length === 1 &&
                        topLevelStatements[0][1][1][3][0][0] === 'if') {

                        var numDefineStatements = 0,
                            walker = uglifyJs.uglify.ast_walker();
                        walker.with_walkers({
                            call: function (expr, args) {
                                if (expr[0] === 'name' && expr[1] === 'define') {
                                    numDefineStatements += 1;
                                }
                            }
                        }, function () {
                            walker.walk(topLevelStatements[0][1][1]);
                        });
                        if (numDefineStatements === 1) {
                            var context = vm.createContext(),
                                factory;
                            context.define = function () {
                                if (arguments.length > 0 && typeof arguments[arguments.length - 1] === 'function') {
                                    factory = arguments[arguments.length - 1];
                                }
                            };
                            context.define.amd = {jQuery: true, multiversion: true, plugins: true};

                            try {
                                vm.runInContext(uglifyJs.uglify.gen_code(topLevelStatements[0]), context);
                            } catch (e) {
                                factory = false;
                            }
                            if (factory) {
                                injectDefineStatementValueAst = uglifyAst.objToAst(factory);
                                topLevelStatements = clonedAsset.parseTree[1] = [];
                                hasFoundPlausibleDefineStatementValueAst = true;
                            }
                        }
                    }
                    if (!hasFoundPlausibleDefineStatementValueAst) {
                        var callDefineAsts = [],
                            walker = uglifyJs.uglify.ast_walker();
                        walker.with_walkers({
                            call: function (expr) {
                                if (expr[0] === 'name' && expr[1] === 'define') {
                                    var stack = walker.stack();
                                    callDefineAsts.push(stack[stack.length - 1]);
                                }
                            }
                        }, function () {
                            walker.walk(clonedAsset.parseTree);
                        });
                        if (callDefineAsts.length === 1) {
                            var moduleName = getModuleName(asset);
                            if (moduleName) {
                                if (asset === startRelation.to) {
                                    // Strip "scripts/" prefix of the main module (hmm, not sure?)
                                    moduleName = moduleName.replace(/^.*\//, "");
                                }
                                var firstArgumentIsString = callDefineAsts[0][2].length > 0 && callDefineAsts[0][2][0][0] === 'string';
                                callDefineAsts[0][2].splice(0, firstArgumentIsString ? 1 : 0, ['string', moduleName]);
                            }
                            injectDefineStatementValueAst = null;
                            hasFoundPlausibleDefineStatementValueAst = true;
                        }
                    }
                    if (injectDefineStatementValueAst) {
                        bundleTopLevelStatements.push(['stat', ['call', ['name', 'define'], [['string', getModuleName(asset)], injectDefineStatementValueAst]]]);
                    }
                    if (!hasFoundPlausibleDefineStatementValueAst) {
                        asset._notAmd = true;
                    }
                    Array.prototype.push.apply(bundleTopLevelStatements, clonedAsset.parseTree[1]);
                });
                startRelation.to.replaceWith(new assetGraph.constructor.assets.JavaScript({
                    url: startRelation.to.url,
                    parseTree: ['toplevel', bundleTopLevelStatements],
                    outgoingRelations: outgoingRelations
                }));
                outgoingRelations.forEach(function (outgoingRelation) {
                    outgoingRelation.refreshHref();
                });
                assetsToBundle.forEach(function (asset) {
                    assetGraph.removeAsset(asset);
                });
            });
        });
        assetsToCleanUp.forEach(function (asset) {
            if (asset.assetGraph && asset.incomingRelations.every(function (incomingRelation) {return assetsToCleanUp.indexOf(incomingRelation.from) !== -1;})) {
                assetGraph.removeAsset(asset);
            }
        });
        assetGraph.recomputeBaseAssets(true);
    };
};
<|endoftext|>


<commit_before>module.exports = {
  tryBranchAutomerge,
};

async function tryBranchAutomerge(config) {
  logger.debug('Checking if we can automerge branch');
  if (!(config.automerge && config.automergeType === 'branch')) {
    return 'no automerge';
  }
  const existingPr = await platform.getBranchPr(config.branchName);
  if (existingPr) {
    return 'automerge aborted - PR exists';
  }
  const branchStatus = await platform.getBranchStatus(
    config.branchName,
    config.requiredStatusChecks
  );
  if (branchStatus === 'success') {
    logger.debug(`Automerging branch`);
    try {
      await platform.mergeBranch(config.branchName);
      logger.info({ branch: config.branchName }, 'Branch automerged');
      return 'automerged'; // Branch no longer exists
    } catch (err) {
      logger.info({ err }, `Failed to automerge branch`);
      return 'failed';
    }
  } else if (['failure', 'error'].includes(branchStatus)) {
    return 'branch status error';
  } else {
    logger.debug(`Branch status is "${branchStatus}" - skipping automerge`);
  }
  return 'no automerge';
}
<commit_msg>fix(github): catch/ignore if required status checks not met yet<commit_after>module.exports = {
  tryBranchAutomerge,
};

async function tryBranchAutomerge(config) {
  logger.debug('Checking if we can automerge branch');
  if (!(config.automerge && config.automergeType === 'branch')) {
    return 'no automerge';
  }
  const existingPr = await platform.getBranchPr(config.branchName);
  if (existingPr) {
    return 'automerge aborted - PR exists';
  }
  const branchStatus = await platform.getBranchStatus(
    config.branchName,
    config.requiredStatusChecks
  );
  if (branchStatus === 'success') {
    logger.debug(`Automerging branch`);
    try {
      await platform.mergeBranch(config.branchName);
      logger.info({ branch: config.branchName }, 'Branch automerged');
      return 'automerged'; // Branch no longer exists
    } catch (err) {
      logger.info({ err }, `Failed to automerge branch`);
      // istanbul ignore if
      if (
        err.message &&
        err.message.includes('required status checks are expected')
      ) {
        return 'not yet';
      }
      return 'failed';
    }
  } else if (['failure', 'error'].includes(branchStatus)) {
    return 'branch status error';
  } else {
    logger.debug(`Branch status is "${branchStatus}" - skipping automerge`);
  }
  return 'no automerge';
}
<|endoftext|>


<commit_before>var conf = {
    job : 'example',
    host: 'http://alembic.local:7000'
};

var formatScriptTag = function(src){
    $.ajax({
        url: src,
        dataType: "jsonp"
    });
};

var pollRemoteHost = function (){
    $.getJSON(conf.host +
              '/job/' +
              conf.job +
              '/api/json?' +
              '&tree=builds[building],name,url' +
              '&jsonp=?',
              function(job) {
                  var building = job.builds[0].building;

                  if  (building === false){
                      $('#status').html('Done!');
                  } else {
                      $('#status').text('Building: ' + job.name);
                  }
              });
};

$('button')
    .click(function(){

      var URL = conf.host +
                '/job/' +
                conf.job +
                '/build';

        formatScriptTag(URL);

        setInterval(
            pollRemoteHost,
            500);

    });
<commit_msg>improved<commit_after>var conf = {
    job : 'example',
    host: 'http://alembic.local:7000'
};

var formatScriptTag = function(src){
    $.ajax({
        url: src,
        dataType: "jsonp"
    });
};

var pollRemoteHost = function (){
    $.getJSON(conf.host +
              '/job/' +
              conf.job +
              '/api/json?' +
              '&tree=builds[building],name,url' +
              '&jsonp=?',
              function(job) {
                  var building = job.builds[0].building;

                  if  (building === false){
                      $('#status').html('Done!');
                  } else {
                      $('#status').text('Building: ' + job.name);
                  }
              });
};

$('button')
    .click(function(){

      var URL = conf.host +
                '/job/' +
                conf.job +
                '/build?delay=0sec';

        formatScriptTag(URL);

        setInterval(
            pollRemoteHost,
            500);

    });
<|endoftext|>


<commit_before>var getPackageLocation = require("./getPackageLocation");
var getPackageConfig   = require("./getPackageConfig");
var getPackages        = require("./getPackages");
var progressBar        = require("./progressBar");
var execSync           = require("./execSync");
var chalk              = require("chalk");

module.exports = function checkUpdatedPackages(packagesLoc) {
  var changedPackages = [];
  var FORCE_VERSION = process.env.FORCE_VERSION;
  FORCE_VERSION = FORCE_VERSION ? FORCE_VERSION.split(",") : [];

  console.log("Checking packages...");

  var packages = getPackages(packagesLoc);

  var tick = progressBar(packages.length);

  var hasTags = !!execSync("git tag");
  var lastTagCommit;
  var lastTag;

  if (hasTags) {
    lastTagCommit = execSync("git rev-list --tags --max-count=1");
    lastTag = execSync("git describe --tags " + lastTagCommit);
  }

  packages.forEach(function (pkg) {
    var cfg = getPackageConfig(packagesLoc, pkg.folder);
    tick(pkg.name);

    if (cfg.private) return;

    if (!hasTags) {
      changedPackages.push(pkg);
      return;
    }

    // check if package has changed since last release
    var diff = FORCE_VERSION.indexOf("*") >= 0 || FORCE_VERSION.indexOf(pkg.name) >= 0 ||
               execSync("git diff " + lastTag + " -- " + getPackageLocation(packagesLoc, pkg.name));
    if (diff) {
      changedPackages.push(pkg);
    }
  });

  if (!changedPackages.length && !FORCE_VERSION.length) {
    console.error(chalk.red("No updated packages to publish."));
    process.exit(1);
  } else {
    return changedPackages;
  }
};
<commit_msg>Detect changes in packages with @ prefix<commit_after>var getPackageLocation = require("./getPackageLocation");
var getPackageConfig   = require("./getPackageConfig");
var getPackages        = require("./getPackages");
var progressBar        = require("./progressBar");
var execSync           = require("./execSync");
var chalk              = require("chalk");

module.exports = function checkUpdatedPackages(packagesLoc) {
  var changedPackages = [];
  var FORCE_VERSION = process.env.FORCE_VERSION;
  FORCE_VERSION = FORCE_VERSION ? FORCE_VERSION.split(",") : [];

  console.log("Checking packages...");

  var packages = getPackages(packagesLoc);

  var tick = progressBar(packages.length);

  var hasTags = !!execSync("git tag");
  var lastTagCommit;
  var lastTag;

  if (hasTags) {
    lastTagCommit = execSync("git rev-list --tags --max-count=1");
    lastTag = execSync("git describe --tags " + lastTagCommit);
  }

  packages.forEach(function (pkg) {
    var cfg = getPackageConfig(packagesLoc, pkg.folder);
    tick(pkg.name);

    if (cfg.private) return;

    if (!hasTags) {
      changedPackages.push(pkg);
      return;
    }

    // check if package has changed since last release
    var diff = FORCE_VERSION.indexOf("*") >= 0 || FORCE_VERSION.indexOf(pkg.name) >= 0 ||
               execSync("git diff " + lastTag + " -- " + getPackageLocation(packagesLoc, pkg.folder));
    if (diff) {
      changedPackages.push(pkg);
    }
  });

  if (!changedPackages.length && !FORCE_VERSION.length) {
    console.error(chalk.red("No updated packages to publish."));
    process.exit(1);
  } else {
    return changedPackages;
  }
};
<|endoftext|>


<commit_before>var Crypto = require('crypto');
var semver = require('semver');

var Datasource = require('./datasource');

// Map configuration object

/// API: Create MapConfig from configuration object
//
/// @param obj js MapConfiguration object, see
///        http://github.com/CartoDB/Windshaft/wiki/MapConfig-specification
///
function MapConfig(config, datasource) {
    // TODO: inject defaults ?
    this._cfg = config;

    if ( ! semver.satisfies(this.version(), '>= 1.0.0 <= 1.6.0') ) {
        throw new Error("Unsupported layergroup configuration version " + this.version());
    }

    if ( ! this._cfg.hasOwnProperty('layers') ) {
        throw new Error("Missing layers array from layergroup config");
    }

    this._cfg.layers.forEach(function(layer, i) {
    if ( ! layer.hasOwnProperty('options') ) {
        throw new Error("Missing options from layer " + i + " of layergroup config");
    }
    // NOTE: interactivity used to be a string as of version 1.0.0
    if ( Array.isArray(layer.options.interactivity) ) {
        layer.options.interactivity = layer.options.interactivity.join(',');
    }
  });

    /**
    * @type {Datasource}
    */
    this._datasource = datasource;

    this._id = null;
}

function md5Hash(s) {
    return Crypto.createHash('md5').update(s, 'binary').digest('hex');
}

/// API: Get serialized version of this MapConfig
MapConfig.prototype.serialize = function() {
    if (this._datasource.isEmpty()) {
        return JSON.stringify(this._cfg);
    }
    return JSON.stringify({
        cfg: this._cfg,
        ds: this._datasource.obj()
    });
};

/// API: Get identifier for this MapConfig
MapConfig.prototype.id = function() {
    if (this._id === null) {
        this._id = md5Hash(JSON.stringify(this._cfg));
    }
    //debug('MapConfig.id=%s', this._id);
    return this._id;
};

/// API: Get configuration object of this MapConfig
MapConfig.prototype.obj = function() {
    return this._cfg;
};

MapConfig.prototype.version = function() {
    return this._cfg.version || '1.0.0';
};

MapConfig.prototype.setDbParams = function(dbParams) {
    this._cfg.dbparams = dbParams;
    this.flush();
};

MapConfig.prototype.flush = function() {
    // flush id so it gets recalculated
    this._id = null;
};

/// API: Get type string of given layer
//
/// @param num layer index (0-based)
/// @returns a type string, as read from the layer
///
MapConfig.prototype.layerType = function(num) {
    var lyr = this.getLayer(num);
    if ( ! lyr ) {
        return undefined;
    }
    return this.getType(lyr.type);
};

MapConfig.prototype.getType = function(type) {
    return getType(type);
};

function getType(type) {
    // TODO: check validity of other types ?
    return (!type || type === 'cartodb') ? 'mapnik' : type;
}

MapConfig.prototype.setBufferSize = function (bufferSize) {
    this._cfg.bufferSize = bufferSize;
    this.flush();
    return this;
};

MapConfig.prototype.getBufferSize = function (format) {
    if (this._cfg.buffersize && isValidBufferSize(this._cfg.buffersize[format])) {
        return parseInt(this._cfg.buffersize[format], 10);
    }

    return undefined;
};

function isValidBufferSize(value) {
    return Number.isFinite(parseInt(value, 10));
}

MapConfig.prototype.hasIncompatibleLayers = function () {
    return !this.isVectorOnlyLayergroup() && this.hasVectorLayer();
};

MapConfig.prototype.isVectorOnlyLayergroup = function () {
    const layers = this.getLayers();
    let isVectorOnlyLayergroup = false;

    if (!layers.length) {
        return isVectorOnlyLayergroup;
    }

    isVectorOnlyLayergroup = true;

    for (const layer of layers) {
        if (!this.isVectorLayer(layer)) {
            isVectorOnlyLayergroup = false;
            break;
        }
    }

    return isVectorOnlyLayergroup;
};

MapConfig.prototype.hasVectorLayer = function () {
    const layers = this.getLayers();
    let hasVectorLayer = false;

    for (const layer of layers) {
        if (this.isVectorLayer(layer)) {
            hasVectorLayer = true;
            break;
        }
    }

    return hasVectorLayer;
};

MapConfig.prototype.isVectorLayer = function (layer) {
    return getType(layer.type) === 'mapnik' &&
        typeof layer.options.sql === 'string' &&
        layer.options.cartocss === undefined &&
        layer.options.cartocss_version === undefined;
};

/*****************************************************************************
 * Layers
 ****************************************************************************/

MapConfig.prototype.getLayerId = function(layerIndex) {
    return getLayerId(this._cfg, layerIndex);
};

function getLayerId(rawMapConfig, layerIndex) {
    var layer = rawMapConfig.layers[layerIndex];
    if (layer.id) {
        return layer.id;
    }

    var layerType = getType(layer.type);
    var layerId = 'layer' + getLayerIndexByType(rawMapConfig, layerType, layerIndex);
    if (layerType !== 'mapnik') {
        layerId = layerType + '-' + layerId;
    }
    return layerId;
}

MapConfig.prototype.getIndexByLayerId = function (layerId) {
    var layers = this.getLayers();

    for (var i = 0; i < layers.length; i++) {
        if (layers[i].id === layerId) {
            return i;
        }
    }

    return -1;
};

/// API: Get layer by index
//
/// @returns undefined on invalid index
///
MapConfig.prototype.getLayer = function(layerIndex) {
    return this._cfg.layers[layerIndex];
};

MapConfig.prototype.getLayers = function() {
    return this._cfg.layers.map(function(_layer, layerIndex) {
        return this.getLayer(layerIndex);
    }.bind(this));
};

MapConfig.prototype.getLayerIndexByType = function(type, mapConfigLayerIdx) {
    return getLayerIndexByType(this._cfg, type, mapConfigLayerIdx);
};

function getLayerIndexByType(rawMapConfig, type, mapConfigLayerIdx) {
    var typeLayerIndex = 0;
    var mapConfigToTypeLayers = {};

    rawMapConfig.layers.forEach(function (layer, layerIdx) {
        if (getType(layer.type) === type) {
            mapConfigToTypeLayers[layerIdx] = typeLayerIndex++;
        }
    });

    return mapConfigToTypeLayers[mapConfigLayerIdx];
}

MapConfig.prototype.getLayerOption = function(layerIndex, optionName, defaultValue) {
    var layerOption = defaultValue;
    var layer = this.getLayer(layerIndex);
    if (layer && layer.options.hasOwnProperty(optionName)) {
        layerOption = layer.options[optionName];
    }
    return layerOption;
};

/*****************************************************************************
 * Datasource
 ****************************************************************************/

MapConfig.prototype.getLayerDatasource = function (layerIndex) {
    var datasource = this._datasource.getLayerDatasource(layerIndex) || {};

    var layerSrid = this.getLayerOption(layerIndex, 'srid');
    if (layerSrid) {
        datasource.srid = layerSrid;
    }

    return datasource;
};

/**
 * À la Factory method
 *
 * @param {Object} rawConfig
 * @param {Datasource} [datasource=Datasource.EmptyDatasource()]
 * @returns {MapConfig}
 */
function create(rawConfig, datasource) {
    if (rawConfig.ds) {
        return new MapConfig(rawConfig.cfg, new Datasource(rawConfig.ds));
    }
    datasource = datasource || Datasource.EmptyDatasource();
    return new MapConfig(rawConfig, datasource);
}

module.exports = MapConfig;
// Factory like method to create MapConfig objects when you are unsure about being
// able to provide all the MapConfig collaborators or you have to create a MapConfig
// object from a serialized version
module.exports.create = create;

module.exports.getLayerId = getLayerId;
<commit_msg>Use layer index approach to identify vector layergroups<commit_after>var Crypto = require('crypto');
var semver = require('semver');

var Datasource = require('./datasource');

// Map configuration object

/// API: Create MapConfig from configuration object
//
/// @param obj js MapConfiguration object, see
///        http://github.com/CartoDB/Windshaft/wiki/MapConfig-specification
///
function MapConfig(config, datasource) {
    // TODO: inject defaults ?
    this._cfg = config;

    if ( ! semver.satisfies(this.version(), '>= 1.0.0 <= 1.6.0') ) {
        throw new Error("Unsupported layergroup configuration version " + this.version());
    }

    if ( ! this._cfg.hasOwnProperty('layers') ) {
        throw new Error("Missing layers array from layergroup config");
    }

    this._cfg.layers.forEach(function(layer, i) {
    if ( ! layer.hasOwnProperty('options') ) {
        throw new Error("Missing options from layer " + i + " of layergroup config");
    }
    // NOTE: interactivity used to be a string as of version 1.0.0
    if ( Array.isArray(layer.options.interactivity) ) {
        layer.options.interactivity = layer.options.interactivity.join(',');
    }
  });

    /**
    * @type {Datasource}
    */
    this._datasource = datasource;

    this._id = null;
}

function md5Hash(s) {
    return Crypto.createHash('md5').update(s, 'binary').digest('hex');
}

/// API: Get serialized version of this MapConfig
MapConfig.prototype.serialize = function() {
    if (this._datasource.isEmpty()) {
        return JSON.stringify(this._cfg);
    }
    return JSON.stringify({
        cfg: this._cfg,
        ds: this._datasource.obj()
    });
};

/// API: Get identifier for this MapConfig
MapConfig.prototype.id = function() {
    if (this._id === null) {
        this._id = md5Hash(JSON.stringify(this._cfg));
    }
    //debug('MapConfig.id=%s', this._id);
    return this._id;
};

/// API: Get configuration object of this MapConfig
MapConfig.prototype.obj = function() {
    return this._cfg;
};

MapConfig.prototype.version = function() {
    return this._cfg.version || '1.0.0';
};

MapConfig.prototype.setDbParams = function(dbParams) {
    this._cfg.dbparams = dbParams;
    this.flush();
};

MapConfig.prototype.flush = function() {
    // flush id so it gets recalculated
    this._id = null;
};

/// API: Get type string of given layer
//
/// @param num layer index (0-based)
/// @returns a type string, as read from the layer
///
MapConfig.prototype.layerType = function(num) {
    var lyr = this.getLayer(num);
    if ( ! lyr ) {
        return undefined;
    }
    return this.getType(lyr.type);
};

MapConfig.prototype.getType = function(type) {
    return getType(type);
};

function getType(type) {
    // TODO: check validity of other types ?
    return (!type || type === 'cartodb') ? 'mapnik' : type;
}

MapConfig.prototype.setBufferSize = function (bufferSize) {
    this._cfg.bufferSize = bufferSize;
    this.flush();
    return this;
};

MapConfig.prototype.getBufferSize = function (format) {
    if (this._cfg.buffersize && isValidBufferSize(this._cfg.buffersize[format])) {
        return parseInt(this._cfg.buffersize[format], 10);
    }

    return undefined;
};

function isValidBufferSize(value) {
    return Number.isFinite(parseInt(value, 10));
}

MapConfig.prototype.hasIncompatibleLayers = function () {
    return !this.isVectorOnlyLayergroup() && this.hasVectorLayer();
};

MapConfig.prototype.isVectorOnlyLayergroup = function () {
    const layers = this.getLayers();
    let isVectorOnlyLayergroup = false;

    if (!layers.length) {
        return isVectorOnlyLayergroup;
    }

    isVectorOnlyLayergroup = true;

    for (let index = 0; index < layers.length; index++) {
        if (!this.isVectorLayer(index)) {
            isVectorOnlyLayergroup = false;
            break;
        }
    }

    return isVectorOnlyLayergroup;
};

MapConfig.prototype.hasVectorLayer = function () {
    const layers = this.getLayers();
    let hasVectorLayer = false;

    for (let index = 0; index < layers.length; index++) {
        if (this.isVectorLayer(index)) {
            hasVectorLayer = true;
            break;
        }
    }

    return hasVectorLayer;
};

MapConfig.prototype.isVectorLayer = function (index) {
    const layer = this.getLayer(index);
    const type =  getType(layer.type);
    const sql = this.getLayerOption(index, 'sql');
    const cartocss = this.getLayerOption(index, 'cartocss');
    const cartocssVersion = this.getLayerOption(index, 'cartocss_version');

    return type === 'mapnik' && typeof sql === 'string' && cartocss === undefined && cartocssVersion === undefined;
};

/*****************************************************************************
 * Layers
 ****************************************************************************/

MapConfig.prototype.getLayerId = function(layerIndex) {
    return getLayerId(this._cfg, layerIndex);
};

function getLayerId(rawMapConfig, layerIndex) {
    var layer = rawMapConfig.layers[layerIndex];
    if (layer.id) {
        return layer.id;
    }

    var layerType = getType(layer.type);
    var layerId = 'layer' + getLayerIndexByType(rawMapConfig, layerType, layerIndex);
    if (layerType !== 'mapnik') {
        layerId = layerType + '-' + layerId;
    }
    return layerId;
}

MapConfig.prototype.getIndexByLayerId = function (layerId) {
    var layers = this.getLayers();

    for (var i = 0; i < layers.length; i++) {
        if (layers[i].id === layerId) {
            return i;
        }
    }

    return -1;
};

/// API: Get layer by index
//
/// @returns undefined on invalid index
///
MapConfig.prototype.getLayer = function(layerIndex) {
    return this._cfg.layers[layerIndex];
};

MapConfig.prototype.getLayers = function() {
    return this._cfg.layers.map(function(_layer, layerIndex) {
        return this.getLayer(layerIndex);
    }.bind(this));
};

MapConfig.prototype.getLayerIndexByType = function(type, mapConfigLayerIdx) {
    return getLayerIndexByType(this._cfg, type, mapConfigLayerIdx);
};

function getLayerIndexByType(rawMapConfig, type, mapConfigLayerIdx) {
    var typeLayerIndex = 0;
    var mapConfigToTypeLayers = {};

    rawMapConfig.layers.forEach(function (layer, layerIdx) {
        if (getType(layer.type) === type) {
            mapConfigToTypeLayers[layerIdx] = typeLayerIndex++;
        }
    });

    return mapConfigToTypeLayers[mapConfigLayerIdx];
}

MapConfig.prototype.getLayerOption = function(layerIndex, optionName, defaultValue) {
    var layerOption = defaultValue;
    var layer = this.getLayer(layerIndex);
    if (layer && layer.options.hasOwnProperty(optionName)) {
        layerOption = layer.options[optionName];
    }
    return layerOption;
};

/*****************************************************************************
 * Datasource
 ****************************************************************************/

MapConfig.prototype.getLayerDatasource = function (layerIndex) {
    var datasource = this._datasource.getLayerDatasource(layerIndex) || {};

    var layerSrid = this.getLayerOption(layerIndex, 'srid');
    if (layerSrid) {
        datasource.srid = layerSrid;
    }

    return datasource;
};

/**
 * À la Factory method
 *
 * @param {Object} rawConfig
 * @param {Datasource} [datasource=Datasource.EmptyDatasource()]
 * @returns {MapConfig}
 */
function create(rawConfig, datasource) {
    if (rawConfig.ds) {
        return new MapConfig(rawConfig.cfg, new Datasource(rawConfig.ds));
    }
    datasource = datasource || Datasource.EmptyDatasource();
    return new MapConfig(rawConfig, datasource);
}

module.exports = MapConfig;
// Factory like method to create MapConfig objects when you are unsure about being
// able to provide all the MapConfig collaborators or you have to create a MapConfig
// object from a serialized version
module.exports.create = create;

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


<commit_before>var carto = require('carto');
var _ = require('underscore');
var PSQL = require('./psql');
var Step = require('step');
var torque_reference = require('torque.js').cartocss_reference;

//
// given cartocss return javascript properties
//
// @param required optional array of required properties
//
// @throw Error if required properties are not found
//
function attrsFromCartoCSS(cartocss, required) {
  var attrs_keys = {
    '-torque-frame-count': 'steps',
    '-torque-resolution': 'resolution',
    '-torque-animation-duration': 'animationDuration',
    '-torque-aggregation-function': 'countby',
    '-torque-time-attribute': 'column',
    '-torque-data-aggregation': 'data_aggregation'
  };
  carto.tree.Reference.setData(torque_reference.version.latest);
  var env = {
      benchmark: false,
      validation_data: false,
      effects: [],
      errors: [],
      error: function(e) {
        this.errors.push(e);
      }
  };
  var root = (carto.Parser(env)).parse(cartocss);
  var definitions = root.toList(env);
  var rules = getMapProperties(definitions, env);
  var attrs = {};
  for (var k in attrs_keys) {
    if (rules[k]) {
      attrs[attrs_keys[k]] = rules[k].value.toString();
    } else if ( required && required.indexOf(attrs_keys[k]) != -1 ) {
        throw new Error("Missing required property '" + k + "' in torque layer CartoCSS");
    }
  }
  return attrs;
}

//
// get rules from Map definition
// stores errors in env.error
//
function getMapProperties(definitions, env) {
  var rules = {};
  definitions.filter(function(r) {
      return r.elements.join('') === 'Map';
  }).forEach(function(r) {
      for (var i = 0; i < r.rules.length; i++) {
          var key = r.rules[i].name;
          rules[key] = r.rules[i].ev(env);
      }
  });
  return rules;
}

//
// check layer and raise an exception is some error is found
//
// @throw Error if missing or malformed CartoCSS
//
function _checkLayerAttributes(layerConfig) {
  var cartoCSS = layerConfig.options.cartocss;
  if (!cartoCSS)
    throw Error("cartocss can't be undefined");
  var checks = ['steps', 'resolution', 'column'];
  var attrs = attrsFromCartoCSS(cartoCSS, checks);
  return attrs;
}

function Renderer(layer, sql, attrs) {
  this.sql = sql;
  this.attrs = attrs;
  this.layer_sql = layer.options.sql;
}

Renderer.prototype = {
  /// API: renders a tile with the Renderer configuration
  /// @param x tile x coordinate
  /// @param y tile y coordinate
  /// @param z tile zoom
  /// callback: will be called when done using nodejs protocol (err, data)
  getTile: function(x, y, z, callback) {
    _getTileData(this.sql, {x: x, y: y}, z, this.attrs, this.layer_sql, callback);
  }
};

/// API: initializes the renderer, it should be called once
/// @param options initialization options
//      - sqlClass: class used to access postgres, by default is PSQL
function TorqueFactory(options) {
    this.options = options || {};
    _.defaults(this.options, {
      sqlClass: PSQL
    });
    if (this.options.sqlClass) {
      this.sqlClass = this.options.sqlClass;
    }
}

TorqueFactory.prototype = {
  /// API: renderer name, use for information pourposes
  name: 'torque',

  /// API: tile formats this module is able to render
  supported_formats: ['json.torque', 'bin.torque'],

  /// API: creates a renderer
  /// @param mapConfig json object with full mapConfig
  /// @param dbParams json object with database connection params (host, dbname, user and pass)
  /// @param format one of the supported_formats
  /// @param layer layer index inside mapConfig (optional)
  /// @param callback function(err, renderer) called when method finishes
  getRenderer: function(mapConfig, dbParams, format, layer, callback) {
    if (arguments.length === 4) {
      callback = layer;
      callback(new Error("torque renderer only supports a single layer"))
      return;
    }
    if (!_.contains(this.supported_formats, format)) {
      callback(new Error("format not supported: " + format));
      return;
    }
    if (mapConfig.layers[layer] === undefined) {
      callback(new Error("layer index is greater than number of layers"));
      return;
    }
    var pgSQL = sql(dbParams, this.sqlClass);
    fetchMapConfigAttributes(pgSQL, mapConfig, dbParams, layer, function(err, params){
      if (err) {
        callback(err);
        return;
      }
      callback(null, new Renderer(mapConfig.layers[layer], pgSQL, params, layer));
    });
  }

};

module.exports = TorqueFactory;

// returns an array of errors if the mapconfig is not supported or contains errors
// errors is empty is the configuration is ok
// dbParams: host, dbname, user and pass
// layer: optional, if is specified only a layer is checked
function fetchMapConfigAttributes(sql, mapConfig, dbParams, layer_id, callback) {

  // only one layer supported
  var layer = mapConfig.layers[layer_id];

  if (!layer) {
    callback(new Error("mapconfig does not contain any torque layer"));
    return;
  }

  // check attrs
  try { var attrs = _checkLayerAttributes(layer); }
  catch (e) { callback(e); return; }

  // fetch layer attributes to check the query and so on is ok
  var layer_sql = layer.options.sql;
  fetchLayerAttributes(sql, layer_sql, attrs, callback);
}

function sql(dbParams, sqlClass) {
  return function(query, callback) {
    var pg = new sqlClass(dbParams);
    pg.query(query, callback);
  };
}

function format(str) {
  for(var i = 1; i < arguments.length; ++i) {
    var attrs = arguments[i];
    for(var attr in attrs) {
      str = str.replace(RegExp('\\{' + attr + '\\}', 'g'), attrs[attr]);
    }
  }
  return str;
}

function fetchLayerAttributes(sql, layer_sql, attrs, callback) {
  var is_time;

  Step(

  //
  // first step, fetch the schema to know if torque colum is time column
  //
  function fetchSqlSchema() {
    var query = format("select * from ({sql}) __torque_wrap_sql limit 0", { sql: layer_sql });
    sql(query, this);
  },

  //
  // second step, get time bounds to calculate step
  //
  function fetchProps(err, data) {
    if (err) throw err;
    if ( ! data ) {
      console.log("ERROR: layer query '" + layer_query + "' returned no data");
      throw new Error("Layer query returned no data");
    }
    is_time = data.fields[attrs.column].type === 'date';
    var column_conv = attrs.column;
    if (is_time){
      max_tmpl = "date_part('epoch', max({column}))";
      min_tmpl = "date_part('epoch', min({column}))";
      column_conv = format("date_part('epoch', {column})", attrs);
    } else {
      max_tmpl = "max({column})";
      min_tmpl = "min({column})";
    }

    max_col = format(max_tmpl, { column: attrs.column });
    min_col = format(min_tmpl, { column: attrs.column });
    var sql_stats = " SELECT " +
        "st_xmax(st_envelope(st_collect(the_geom))) xmax, " +
        "st_ymax(st_envelope(st_collect(the_geom))) ymax, " +
        "st_xmin(st_envelope(st_collect(the_geom))) xmin, " +
        "st_ymin(st_envelope(st_collect(the_geom))) ymin, " +
        "count(*) as num_steps, " +
        "{max_col} max_date, " +
        "{min_col} min_date FROM  ({sql}) __torque_wrap_sql ";

    var query = format(sql_stats, {
      max_col: max_col,
      min_col: min_col,
      column: column_conv,
      sql: layer_sql
    });
    sql(query, this);
  },

  //
  // prepare metadata needed to render the tiles
  //
  function generateMetadata(err, data) {
    if(err) {
      callback(err);
      return;
    }
    data = data.rows[0];
    callback(null, {
      start: data.min_date,
      end: data.max_date,
      step: (data.max_date - data.min_date)/Math.min(attrs.steps, data.num_steps>>0),
      data_steps: data.num_steps >> 0,
      is_time: is_time,
      bounds: [
        [data.ymin, data.xmin],
        [data.ymax, data.xmax]
      ]
    });
  });
}

function _getTileData(sql, coord, zoom, layer_sql, attrs, callback) {
    //var prof_fetch_time = Profiler.metric('ProviderJSON:tile_fetch_time').start()

    var column_conv = attrs.column;

    if(attrs.is_time) {
      column_conv = format("date_part('epoch', {column})", attrs);
    }

    var tile_sql = "" +
      "WITH " +
      "par AS (" +
      "  SELECT CDB_XYZ_Resolution({zoom})*{resolution} as res" +
      ",  256/{resolution} as tile_size" +
      ", CDB_XYZ_Extent({x}, {y}, {zoom}) as ext "  +
      ")," +
      "cte AS ( "+
      "  SELECT ST_SnapToGrid(i.the_geom_webmercator, p.res) g" +
      ", {countby} c" +
      ", floor(({column_conv} - {start})/{step}) d" +
      "  FROM ({_sql}) i, par p " +
      "  WHERE i.the_geom_webmercator && p.ext " +
      "  GROUP BY g, d" +
      ") " +
      "" +
      "SELECT (st_x(g)-st_xmin(p.ext))/p.res x__uint8, " +
      "       (st_y(g)-st_ymin(p.ext))/p.res y__uint8," +
      " array_agg(c) vals__uint8," +
      " array_agg(d) dates__uint16" +
      // the tile_size where are needed because the overlaps query in cte subquery includes the points
      // in the left and bottom borders of the tile
      " FROM cte, par p where (st_y(g)-st_ymin(p.ext))/p.res < tile_size and (st_x(g)-st_xmin(p.ext))/p.res < tile_size GROUP BY x__uint8, y__uint8";

    var query = format(tile_sql, this.options, {
      zoom: zoom,
      x: coord.x,
      y: coord.y,
      column_conv: column_conv,
      _sql: layer_sql
    });

    sql(query, function (err, data) {
      if (err) {
        callback({ error: 'problem fetching data' });
      } else {
        callback(null, data.rows);
      }
      //prof_fetch_time.end();
    });
}
<commit_msg>documented sqlClass interface for torque<commit_after>var carto = require('carto');
var _ = require('underscore');
var PSQL = require('./psql');
var Step = require('step');
var torque_reference = require('torque.js').cartocss_reference;

//
// given cartocss return javascript properties
//
// @param required optional array of required properties
//
// @throw Error if required properties are not found
//
function attrsFromCartoCSS(cartocss, required) {
  var attrs_keys = {
    '-torque-frame-count': 'steps',
    '-torque-resolution': 'resolution',
    '-torque-animation-duration': 'animationDuration',
    '-torque-aggregation-function': 'countby',
    '-torque-time-attribute': 'column',
    '-torque-data-aggregation': 'data_aggregation'
  };
  carto.tree.Reference.setData(torque_reference.version.latest);
  var env = {
      benchmark: false,
      validation_data: false,
      effects: [],
      errors: [],
      error: function(e) {
        this.errors.push(e);
      }
  };
  var root = (carto.Parser(env)).parse(cartocss);
  var definitions = root.toList(env);
  var rules = getMapProperties(definitions, env);
  var attrs = {};
  for (var k in attrs_keys) {
    if (rules[k]) {
      attrs[attrs_keys[k]] = rules[k].value.toString();
    } else if ( required && required.indexOf(attrs_keys[k]) != -1 ) {
        throw new Error("Missing required property '" + k + "' in torque layer CartoCSS");
    }
  }
  return attrs;
}

//
// get rules from Map definition
// stores errors in env.error
//
function getMapProperties(definitions, env) {
  var rules = {};
  definitions.filter(function(r) {
      return r.elements.join('') === 'Map';
  }).forEach(function(r) {
      for (var i = 0; i < r.rules.length; i++) {
          var key = r.rules[i].name;
          rules[key] = r.rules[i].ev(env);
      }
  });
  return rules;
}

//
// check layer and raise an exception is some error is found
//
// @throw Error if missing or malformed CartoCSS
//
function _checkLayerAttributes(layerConfig) {
  var cartoCSS = layerConfig.options.cartocss;
  if (!cartoCSS)
    throw Error("cartocss can't be undefined");
  var checks = ['steps', 'resolution', 'column'];
  var attrs = attrsFromCartoCSS(cartoCSS, checks);
  return attrs;
}

function Renderer(layer, sql, attrs) {
  this.sql = sql;
  this.attrs = attrs;
  this.layer_sql = layer.options.sql;
}

Renderer.prototype = {
  /// API: renders a tile with the Renderer configuration
  /// @param x tile x coordinate
  /// @param y tile y coordinate
  /// @param z tile zoom
  /// callback: will be called when done using nodejs protocol (err, data)
  getTile: function(x, y, z, callback) {
    _getTileData(this.sql, {x: x, y: y}, z, this.attrs, this.layer_sql, callback);
  }
};

/// API: initializes the renderer, it should be called once
/// @param options initialization options
//      - sqlClass: class used to access postgres, by default is PSQL
//          this addapter should be this interface
//           - constructor(params) where params should contain host, port, database, user, password.
//                                 the class is always constructed with dbParams passed to getRender as-is
//
//           - query(sql, callback(data)) -> gets an SQL query and return a javasrip object with { schema: {}, rows: []}
//                          see CartoDB-SQL-API response reference for more datails (link needed)
function TorqueFactory(options) {
    this.options = options || {};
    _.defaults(this.options, {
      sqlClass: PSQL
    });
    if (this.options.sqlClass) {
      this.sqlClass = this.options.sqlClass;
    }
}

TorqueFactory.prototype = {
  /// API: renderer name, use for information pourposes
  name: 'torque',

  /// API: tile formats this module is able to render
  supported_formats: ['json.torque', 'bin.torque'],

  /// API: creates a renderer
  /// @param mapConfig json object with full mapConfig
  /// @param dbParams json object with database connection params (host, dbname, user and pass)
  /// @param format one of the supported_formats
  /// @param layer layer index inside mapConfig (optional)
  /// @param callback function(err, renderer) called when method finishes
  getRenderer: function(mapConfig, dbParams, format, layer, callback) {
    if (arguments.length === 4) {
      callback = layer;
      callback(new Error("torque renderer only supports a single layer"))
      return;
    }
    if (!_.contains(this.supported_formats, format)) {
      callback(new Error("format not supported: " + format));
      return;
    }
    if (mapConfig.layers[layer] === undefined) {
      callback(new Error("layer index is greater than number of layers"));
      return;
    }
    var pgSQL = sql(dbParams, this.sqlClass);
    fetchMapConfigAttributes(pgSQL, mapConfig, dbParams, layer, function(err, params){
      if (err) {
        callback(err);
        return;
      }
      callback(null, new Renderer(mapConfig.layers[layer], pgSQL, params, layer));
    });
  }

};

module.exports = TorqueFactory;

// returns an array of errors if the mapconfig is not supported or contains errors
// errors is empty is the configuration is ok
// dbParams: host, dbname, user and pass
// layer: optional, if is specified only a layer is checked
function fetchMapConfigAttributes(sql, mapConfig, dbParams, layer_id, callback) {

  // only one layer supported
  var layer = mapConfig.layers[layer_id];

  if (!layer) {
    callback(new Error("mapconfig does not contain any torque layer"));
    return;
  }

  // check attrs
  try { var attrs = _checkLayerAttributes(layer); }
  catch (e) { callback(e); return; }

  // fetch layer attributes to check the query and so on is ok
  var layer_sql = layer.options.sql;
  fetchLayerAttributes(sql, layer_sql, attrs, callback);
}

function sql(dbParams, sqlClass) {
  return function(query, callback) {
    var pg = new sqlClass(dbParams);
    pg.query(query, callback);
  };
}

function format(str) {
  for(var i = 1; i < arguments.length; ++i) {
    var attrs = arguments[i];
    for(var attr in attrs) {
      str = str.replace(RegExp('\\{' + attr + '\\}', 'g'), attrs[attr]);
    }
  }
  return str;
}

function fetchLayerAttributes(sql, layer_sql, attrs, callback) {
  var is_time;

  Step(

  //
  // first step, fetch the schema to know if torque colum is time column
  //
  function fetchSqlSchema() {
    var query = format("select * from ({sql}) __torque_wrap_sql limit 0", { sql: layer_sql });
    sql(query, this);
  },

  //
  // second step, get time bounds to calculate step
  //
  function fetchProps(err, data) {
    if (err) throw err;
    if ( ! data ) {
      console.log("ERROR: layer query '" + layer_query + "' returned no data");
      throw new Error("Layer query returned no data");
    }
    is_time = data.fields[attrs.column].type === 'date';
    var column_conv = attrs.column;
    if (is_time){
      max_tmpl = "date_part('epoch', max({column}))";
      min_tmpl = "date_part('epoch', min({column}))";
      column_conv = format("date_part('epoch', {column})", attrs);
    } else {
      max_tmpl = "max({column})";
      min_tmpl = "min({column})";
    }

    max_col = format(max_tmpl, { column: attrs.column });
    min_col = format(min_tmpl, { column: attrs.column });
    var sql_stats = " SELECT " +
        "st_xmax(st_envelope(st_collect(the_geom))) xmax, " +
        "st_ymax(st_envelope(st_collect(the_geom))) ymax, " +
        "st_xmin(st_envelope(st_collect(the_geom))) xmin, " +
        "st_ymin(st_envelope(st_collect(the_geom))) ymin, " +
        "count(*) as num_steps, " +
        "{max_col} max_date, " +
        "{min_col} min_date FROM  ({sql}) __torque_wrap_sql ";

    var query = format(sql_stats, {
      max_col: max_col,
      min_col: min_col,
      column: column_conv,
      sql: layer_sql
    });
    sql(query, this);
  },

  //
  // prepare metadata needed to render the tiles
  //
  function generateMetadata(err, data) {
    if(err) {
      callback(err);
      return;
    }
    data = data.rows[0];
    callback(null, {
      start: data.min_date,
      end: data.max_date,
      step: (data.max_date - data.min_date)/Math.min(attrs.steps, data.num_steps>>0),
      data_steps: data.num_steps >> 0,
      is_time: is_time,
      bounds: [
        [data.ymin, data.xmin],
        [data.ymax, data.xmax]
      ]
    });
  });
}

function _getTileData(sql, coord, zoom, layer_sql, attrs, callback) {
    //var prof_fetch_time = Profiler.metric('ProviderJSON:tile_fetch_time').start()

    var column_conv = attrs.column;

    if(attrs.is_time) {
      column_conv = format("date_part('epoch', {column})", attrs);
    }

    var tile_sql = "" +
      "WITH " +
      "par AS (" +
      "  SELECT CDB_XYZ_Resolution({zoom})*{resolution} as res" +
      ",  256/{resolution} as tile_size" +
      ", CDB_XYZ_Extent({x}, {y}, {zoom}) as ext "  +
      ")," +
      "cte AS ( "+
      "  SELECT ST_SnapToGrid(i.the_geom_webmercator, p.res) g" +
      ", {countby} c" +
      ", floor(({column_conv} - {start})/{step}) d" +
      "  FROM ({_sql}) i, par p " +
      "  WHERE i.the_geom_webmercator && p.ext " +
      "  GROUP BY g, d" +
      ") " +
      "" +
      "SELECT (st_x(g)-st_xmin(p.ext))/p.res x__uint8, " +
      "       (st_y(g)-st_ymin(p.ext))/p.res y__uint8," +
      " array_agg(c) vals__uint8," +
      " array_agg(d) dates__uint16" +
      // the tile_size where are needed because the overlaps query in cte subquery includes the points
      // in the left and bottom borders of the tile
      " FROM cte, par p where (st_y(g)-st_ymin(p.ext))/p.res < tile_size and (st_x(g)-st_xmin(p.ext))/p.res < tile_size GROUP BY x__uint8, y__uint8";

    var query = format(tile_sql, this.options, {
      zoom: zoom,
      x: coord.x,
      y: coord.y,
      column_conv: column_conv,
      _sql: layer_sql
    });

    sql(query, function (err, data) {
      if (err) {
        callback({ error: 'problem fetching data' });
      } else {
        callback(null, data.rows);
      }
      //prof_fetch_time.end();
    });
}
<|endoftext|>


<commit_before>const yarnLockParser = require('@yarnpkg/lockfile');
const configParser = require('../../config');
const depTypeWorker = require('../dep-type');
const npmApi = require('../../manager/npm/registry');
const upath = require('upath');

module.exports = {
  mightBeABrowserLibrary,
  renovatePackageFile,
  renovateMeteorPackageFile,
  renovateDockerfile,
  renovateNodeFile,
  renovateBazelFile,
};

function mightBeABrowserLibrary(packageJson) {
  // return true unless we're sure it's not a browser library
  if (packageJson.private === true) {
    // it's not published
    return false;
  }
  if (packageJson.main === undefined) {
    // it can't be required
    return false;
  }
  // TODO: how can we know if it's a node.js library only, and not browser?
  // Otherwise play it safe and return true
  return true;
}

async function renovatePackageFile(packageFileConfig) {
  const config = { ...packageFileConfig };
  logger.setMeta({
    repository: config.repository,
    packageFile: config.packageFile,
  });
  logger.debug('renovatePakageFile()');
  if (config.npmrc) {
    logger.debug('Setting .npmrc');
    npmApi.setNpmrc(
      config.npmrc,
      config.global ? config.global.exposeEnv : false
    );
  }
  let upgrades = [];
  logger.info(`Processing package file`);

  // Check if config is disabled
  if (config.enabled === false) {
    logger.info('packageFile is disabled');
    return upgrades;
  }

  let yarnLockParsed;
  let packageLockParsed;
  let { yarnLock } = config;
  if (!yarnLock && config.workspaceDir) {
    yarnLock = upath.join(config.workspaceDir, 'yarn.lock');
    logger.debug({ yarnLock }, 'Using workspaces yarn.lock');
  }
  if (yarnLock) {
    try {
      yarnLockParsed = yarnLockParser.parse(await platform.getFile(yarnLock));
      if (yarnLockParsed.type !== 'success') {
        logger.warn(
          { type: yarnLockParsed.type },
          'Error parsing yarn.lock - not success'
        );
        yarnLockParsed = undefined;
      }
      logger.info({ yarnLockParsed });
    } catch (err) {
      logger.warn({ yarnLock }, 'Could not parse yarn.lock');
    }
  } else if (config.packageLock) {
    try {
      packageLockParsed = JSON.parse(
        await platform.getFile(config.packageLock)
      );
      logger.info({ packageLockParsed });
    } catch (err) {
      logger.warn(
        { packageLock: config.packageLock },
        'Could not parse package-lock.json'
      );
    }
  }

  const depTypes = [
    'dependencies',
    'devDependencies',
    'optionalDependencies',
    'peerDependencies',
  ];
  const depTypeConfigs = depTypes.map(depType => {
    const depTypeConfig = configParser.mergeChildConfig(config, {
      ...config[depType],
    });
    depTypeConfig.depType = depType;
    // Always pin devDependencies
    // Pin dependencies if we're pretty sure it's not a browser library
    if (
      depTypeConfig.pinVersions === null &&
      (depType === 'devDependencies' ||
        (depType === 'dependencies' && !mightBeABrowserLibrary(config.content)))
    ) {
      logger.debug('Autodetecting pinVersions = true');
      depTypeConfig.pinVersions = true;
    }
    logger.trace({ config: depTypeConfig }, 'depTypeConfig');
    return configParser.filterConfig(depTypeConfig, 'depType');
  });
  logger.trace({ config: depTypeConfigs }, `depTypeConfigs`);
  for (const depTypeConfig of depTypeConfigs) {
    upgrades = upgrades.concat(
      await depTypeWorker.renovateDepType(
        config.content,
        depTypeConfig,
        packageLockParsed,
        yarnLockParsed
      )
    );
  }
  // Reset logger again
  logger.setMeta({
    repository: config.repository,
    packageFile: config.packageFile,
  });
  if (
    config.lockFileMaintenance.enabled &&
    (config.yarnLock || config.packageLock)
  ) {
    logger.debug('lockFileMaintenance enabled');
    // Maintain lock files
    const lockFileMaintenanceConf = configParser.mergeChildConfig(
      config,
      config.lockFileMaintenance
    );
    lockFileMaintenanceConf.type = 'lockFileMaintenance';
    logger.trace(
      { config: lockFileMaintenanceConf },
      `lockFileMaintenanceConf`
    );
    upgrades.push(configParser.filterConfig(lockFileMaintenanceConf, 'branch'));
  }

  logger.info('Finished processing package file');
  return upgrades;
}

async function renovateMeteorPackageFile(packageFileConfig) {
  const config = { ...packageFileConfig };
  let upgrades = [];
  logger.info(`Processing meteor package file`);

  // Check if config is disabled
  if (config.enabled === false) {
    logger.info('packageFile is disabled');
    return upgrades;
  }
  const content = await platform.getFile(packageFileConfig.packageFile);
  upgrades = upgrades.concat(
    await depTypeWorker.renovateDepType(content, packageFileConfig)
  );
  logger.info('Finished processing package file');
  return upgrades;
}

async function renovateDockerfile(packageFileConfig) {
  let upgrades = [];
  logger.info(`Processing Dockerfile`);

  // Check if config is disabled
  if (packageFileConfig.enabled === false) {
    logger.info('Dockerfile is disabled');
    return upgrades;
  }
  upgrades = upgrades.concat(
    await depTypeWorker.renovateDepType(
      packageFileConfig.content,
      packageFileConfig
    )
  );
  logger.info('Finished processing Dockerfile');
  return upgrades;
}

async function renovateNodeFile(packageFileConfig) {
  let upgrades = [];
  logger.info(`Processing node file`);

  // Check if config is disabled
  if (packageFileConfig.enabled === false) {
    logger.info('node is disabled');
    return upgrades;
  }
  upgrades = upgrades.concat(
    await depTypeWorker.renovateDepType(
      packageFileConfig.content,
      packageFileConfig
    )
  );
  logger.info('Finished processing node file');
  return upgrades;
}

async function renovateBazelFile(packageFileConfig) {
  let upgrades = [];
  logger.info(`Processing bazel WORKSPACE file`);

  // Check if config is disabled
  if (packageFileConfig.enabled === false) {
    logger.info('bazel is disabled');
    return upgrades;
  }
  upgrades = upgrades.concat(
    await depTypeWorker.renovateDepType(
      packageFileConfig.content,
      packageFileConfig
    )
  );
  logger.info('Finished processing bazel file');
  return upgrades;
}
<commit_msg>fix: trace lock files, not info<commit_after>const yarnLockParser = require('@yarnpkg/lockfile');
const configParser = require('../../config');
const depTypeWorker = require('../dep-type');
const npmApi = require('../../manager/npm/registry');
const upath = require('upath');

module.exports = {
  mightBeABrowserLibrary,
  renovatePackageFile,
  renovateMeteorPackageFile,
  renovateDockerfile,
  renovateNodeFile,
  renovateBazelFile,
};

function mightBeABrowserLibrary(packageJson) {
  // return true unless we're sure it's not a browser library
  if (packageJson.private === true) {
    // it's not published
    return false;
  }
  if (packageJson.main === undefined) {
    // it can't be required
    return false;
  }
  // TODO: how can we know if it's a node.js library only, and not browser?
  // Otherwise play it safe and return true
  return true;
}

async function renovatePackageFile(packageFileConfig) {
  const config = { ...packageFileConfig };
  logger.setMeta({
    repository: config.repository,
    packageFile: config.packageFile,
  });
  logger.debug('renovatePakageFile()');
  if (config.npmrc) {
    logger.debug('Setting .npmrc');
    npmApi.setNpmrc(
      config.npmrc,
      config.global ? config.global.exposeEnv : false
    );
  }
  let upgrades = [];
  logger.info(`Processing package file`);

  // Check if config is disabled
  if (config.enabled === false) {
    logger.info('packageFile is disabled');
    return upgrades;
  }

  let yarnLockParsed;
  let packageLockParsed;
  let { yarnLock } = config;
  if (!yarnLock && config.workspaceDir) {
    yarnLock = upath.join(config.workspaceDir, 'yarn.lock');
    logger.debug({ yarnLock }, 'Using workspaces yarn.lock');
  }
  if (yarnLock) {
    try {
      yarnLockParsed = yarnLockParser.parse(await platform.getFile(yarnLock));
      if (yarnLockParsed.type !== 'success') {
        logger.warn(
          { type: yarnLockParsed.type },
          'Error parsing yarn.lock - not success'
        );
        yarnLockParsed = undefined;
      }
      logger.trace({ yarnLockParsed });
    } catch (err) {
      logger.warn({ yarnLock }, 'Could not parse yarn.lock');
    }
  } else if (config.packageLock) {
    try {
      packageLockParsed = JSON.parse(
        await platform.getFile(config.packageLock)
      );
      logger.trace({ packageLockParsed });
    } catch (err) {
      logger.warn(
        { packageLock: config.packageLock },
        'Could not parse package-lock.json'
      );
    }
  }

  const depTypes = [
    'dependencies',
    'devDependencies',
    'optionalDependencies',
    'peerDependencies',
  ];
  const depTypeConfigs = depTypes.map(depType => {
    const depTypeConfig = configParser.mergeChildConfig(config, {
      ...config[depType],
    });
    depTypeConfig.depType = depType;
    // Always pin devDependencies
    // Pin dependencies if we're pretty sure it's not a browser library
    if (
      depTypeConfig.pinVersions === null &&
      (depType === 'devDependencies' ||
        (depType === 'dependencies' && !mightBeABrowserLibrary(config.content)))
    ) {
      logger.debug('Autodetecting pinVersions = true');
      depTypeConfig.pinVersions = true;
    }
    logger.trace({ config: depTypeConfig }, 'depTypeConfig');
    return configParser.filterConfig(depTypeConfig, 'depType');
  });
  logger.trace({ config: depTypeConfigs }, `depTypeConfigs`);
  for (const depTypeConfig of depTypeConfigs) {
    upgrades = upgrades.concat(
      await depTypeWorker.renovateDepType(
        config.content,
        depTypeConfig,
        packageLockParsed,
        yarnLockParsed
      )
    );
  }
  // Reset logger again
  logger.setMeta({
    repository: config.repository,
    packageFile: config.packageFile,
  });
  if (
    config.lockFileMaintenance.enabled &&
    (config.yarnLock || config.packageLock)
  ) {
    logger.debug('lockFileMaintenance enabled');
    // Maintain lock files
    const lockFileMaintenanceConf = configParser.mergeChildConfig(
      config,
      config.lockFileMaintenance
    );
    lockFileMaintenanceConf.type = 'lockFileMaintenance';
    logger.trace(
      { config: lockFileMaintenanceConf },
      `lockFileMaintenanceConf`
    );
    upgrades.push(configParser.filterConfig(lockFileMaintenanceConf, 'branch'));
  }

  logger.info('Finished processing package file');
  return upgrades;
}

async function renovateMeteorPackageFile(packageFileConfig) {
  const config = { ...packageFileConfig };
  let upgrades = [];
  logger.info(`Processing meteor package file`);

  // Check if config is disabled
  if (config.enabled === false) {
    logger.info('packageFile is disabled');
    return upgrades;
  }
  const content = await platform.getFile(packageFileConfig.packageFile);
  upgrades = upgrades.concat(
    await depTypeWorker.renovateDepType(content, packageFileConfig)
  );
  logger.info('Finished processing package file');
  return upgrades;
}

async function renovateDockerfile(packageFileConfig) {
  let upgrades = [];
  logger.info(`Processing Dockerfile`);

  // Check if config is disabled
  if (packageFileConfig.enabled === false) {
    logger.info('Dockerfile is disabled');
    return upgrades;
  }
  upgrades = upgrades.concat(
    await depTypeWorker.renovateDepType(
      packageFileConfig.content,
      packageFileConfig
    )
  );
  logger.info('Finished processing Dockerfile');
  return upgrades;
}

async function renovateNodeFile(packageFileConfig) {
  let upgrades = [];
  logger.info(`Processing node file`);

  // Check if config is disabled
  if (packageFileConfig.enabled === false) {
    logger.info('node is disabled');
    return upgrades;
  }
  upgrades = upgrades.concat(
    await depTypeWorker.renovateDepType(
      packageFileConfig.content,
      packageFileConfig
    )
  );
  logger.info('Finished processing node file');
  return upgrades;
}

async function renovateBazelFile(packageFileConfig) {
  let upgrades = [];
  logger.info(`Processing bazel WORKSPACE file`);

  // Check if config is disabled
  if (packageFileConfig.enabled === false) {
    logger.info('bazel is disabled');
    return upgrades;
  }
  upgrades = upgrades.concat(
    await depTypeWorker.renovateDepType(
      packageFileConfig.content,
      packageFileConfig
    )
  );
  logger.info('Finished processing bazel file');
  return upgrades;
}
<|endoftext|>


<commit_before>/**
 * @class CM_FormField_Suggest
 * @extends CM_FormField_Abstract
 */
var CM_FormField_Suggest = CM_FormField_Abstract.extend({
	_class: 'CM_FormField_Suggest',

	/** @type {jQuery} */
	_$input: null,

	/** @type {jqXHR} */
	_request: null,

	ready: function() {
		var field = this;
		var cardinality = this.getOption("cardinality");
		this._$input = this.$('input[type="text"]');
		var prePopulate = this._$input.data('pre-populate');

		this._$input.removeClass('textinput');
		this._$input.select2({
			width: 'off',
			tags: null,
			dropdownCssClass: this.$el.attr('class'),
			allowClear: true,
			openOnEnter: false,
			maximumSelectionSize: cardinality,
			formatResult: this._formatItem,
			formatSelection: this._formatItemSelected,
			escapeMarkup: function(item) {
				return item;
			},
			query: function(options) {
				if (this._request) {
					this._request.abort();
				}
				this._request = field.ajax('getSuggestions', {'term': options.term, 'options': field.getOptions()}, {
					success: function(results) {
						options.callback({
							results: results
						});
					}
				});
			},
			createSearchChoice: function(term, data) {
				if (field.getOption("enableChoiceCreate")) {
					if ($(data).filter(function() {
						return this.name.localeCompare(term) === 0;
					}).length === 0) {
						return {'id': term, 'name': term, 'new': 1};
					}
				}
			},
			formatSelectionTooBig: null
		}).select2('data', prePopulate);
		this.$('.select2-choices').addClass('textinput');

		this._$input.on("change", function(e) {
			if (!_.isUndefined(e.added)) {
				var items = field._$input.select2("data");
				if (cardinality && items.length > cardinality) {
					items.pop();
					field._$input.select2('data', items);
					field.$el.popover('destroy').popoverInfo(cm.language.get('You can only select {$cardinality} items.', {'cardinality': cardinality}), 2000);
					return false;
				}
				field.onAdd(e.added);
				field.trigger('add', e.added);
			}
			if (!_.isUndefined(e.removed)) {
				field.onDelete(e.removed);
				field.trigger('delete', e.removed);
			}
			field.onChange(field._$input.select2("data"));
			field.trigger('change');
		});

		if (1 == cardinality) {
			this._$input.on('select2-open', function(e) {
				field._$input.select2('data', null);
			});
		}

		this._$input.on('select2-open', function() {
			field.trigger('open');
		});

		this._$input.on('close', function() {
			field.trigger('close');
		});

		this.getForm().$el.bind("reset", function() {
			field._$input.select2('data', null);
		});

		this.onChange(this._$input.select2("data"));
		this.trigger('change');
	},

	/**
	 * @param {Object} item
	 */
	onAdd: function(item) {
	},

	/**
	 * @param {Object} item
	 */
	onDelete: function(item) {
	},

	/**
	 * @param {Object[]} items
	 */
	onChange: function(items) {
	},

	blur: function() {
		this.setTimeout(function() {
			this.$('input.select2-input').blur();
		}, 10);
	},

	/**
	 * @param {Object} item
	 * @return String
	 */
	_formatItem: function(item) {
		var cssClass = 'suggestItem';
		if (item['class']) {
			cssClass += ' ' + _.escape(item['class']);
		}
		var output = '
';
		if (item['img']) {
			output += '

';
		}
		output += '' + _.escape(item['name']) + '';
		if (item['description']) {
			output += '' + _.escape(item['description']) + '';
		}
		output += '
';
		return output;
	},

	/**
	 * @param {Object} item
	 * @return String
	 */
	_formatItemSelected: function(item) {
		var output = _.escape(item['name']);
		if (item['img']) {
			output = '

' + output;
		}
		return output;
	}
});
<commit_msg>Updated 'close' event with 'select2-close'<commit_after>/**
 * @class CM_FormField_Suggest
 * @extends CM_FormField_Abstract
 */
var CM_FormField_Suggest = CM_FormField_Abstract.extend({
	_class: 'CM_FormField_Suggest',

	/** @type {jQuery} */
	_$input: null,

	/** @type {jqXHR} */
	_request: null,

	ready: function() {
		var field = this;
		var cardinality = this.getOption("cardinality");
		this._$input = this.$('input[type="text"]');
		var prePopulate = this._$input.data('pre-populate');

		this._$input.removeClass('textinput');
		this._$input.select2({
			width: 'off',
			tags: null,
			dropdownCssClass: this.$el.attr('class'),
			allowClear: true,
			openOnEnter: false,
			maximumSelectionSize: cardinality,
			formatResult: this._formatItem,
			formatSelection: this._formatItemSelected,
			escapeMarkup: function(item) {
				return item;
			},
			query: function(options) {
				if (this._request) {
					this._request.abort();
				}
				this._request = field.ajax('getSuggestions', {'term': options.term, 'options': field.getOptions()}, {
					success: function(results) {
						options.callback({
							results: results
						});
					}
				});
			},
			createSearchChoice: function(term, data) {
				if (field.getOption("enableChoiceCreate")) {
					if ($(data).filter(function() {
						return this.name.localeCompare(term) === 0;
					}).length === 0) {
						return {'id': term, 'name': term, 'new': 1};
					}
				}
			},
			formatSelectionTooBig: null
		}).select2('data', prePopulate);
		this.$('.select2-choices').addClass('textinput');

		this._$input.on("change", function(e) {
			if (!_.isUndefined(e.added)) {
				var items = field._$input.select2("data");
				if (cardinality && items.length > cardinality) {
					items.pop();
					field._$input.select2('data', items);
					field.$el.popover('destroy').popoverInfo(cm.language.get('You can only select {$cardinality} items.', {'cardinality': cardinality}), 2000);
					return false;
				}
				field.onAdd(e.added);
				field.trigger('add', e.added);
			}
			if (!_.isUndefined(e.removed)) {
				field.onDelete(e.removed);
				field.trigger('delete', e.removed);
			}
			field.onChange(field._$input.select2("data"));
			field.trigger('change');
		});

		if (1 == cardinality) {
			this._$input.on('select2-open', function(e) {
				field._$input.select2('data', null);
			});
		}

		this._$input.on('select2-open', function() {
			field.trigger('open');
		});

		this._$input.on('select2-close', function() {
			field.trigger('close');
		});

		this.getForm().$el.bind("reset", function() {
			field._$input.select2('data', null);
		});

		this.onChange(this._$input.select2("data"));
		this.trigger('change');
	},

	/**
	 * @param {Object} item
	 */
	onAdd: function(item) {
	},

	/**
	 * @param {Object} item
	 */
	onDelete: function(item) {
	},

	/**
	 * @param {Object[]} items
	 */
	onChange: function(items) {
	},

	blur: function() {
		this.setTimeout(function() {
			this.$('input.select2-input').blur();
		}, 10);
	},

	/**
	 * @param {Object} item
	 * @return String
	 */
	_formatItem: function(item) {
		var cssClass = 'suggestItem';
		if (item['class']) {
			cssClass += ' ' + _.escape(item['class']);
		}
		var output = '
';
		if (item['img']) {
			output += '

';
		}
		output += '' + _.escape(item['name']) + '';
		if (item['description']) {
			output += '' + _.escape(item['description']) + '';
		}
		output += '
';
		return output;
	},

	/**
	 * @param {Object} item
	 * @return String
	 */
	_formatItemSelected: function(item) {
		var output = _.escape(item['name']);
		if (item['img']) {
			output = '

' + output;
		}
		return output;
	}
});
<|endoftext|>