<commit_before>var _ = require('lodash');
var request = require('request');
var express = require('express');
var bodyParser = require('body-parser');
var Parse = require('parse/node');
var config = require('./config.json');
var configKeyWhitelist = ['minRating', 'maxRating'];

var loadReviewFromItunes = function(teamSettings, successCallback, errorCallback) {
  var appIdList = teamSettings.get('appIdList');
  var minRating = teamSettings.get('minRating') || 1;
  var maxRating = teamSettings.get('maxRating') || 5;
  var randomAppIndex = Math.floor(Math.random() * (appIdList.length));
  var randomAppId = appIdList[randomAppIndex];
  // Query iTunes
  request(config.itunesApi.baseUrl + randomAppId + '/' + config.itunesApi.responseFormat,
    function(error, response, body) {
      if (!error && response.statusCode == 200) {
        var appName;
        var entries = JSON.parse(body).feed.entry;
        var reviews = _.filter(entries, function(entry) {
          if (entry['im:rating']) {
            // All but the first entry have that property.
            if (entry['im:rating'].label >= minRating && entry['im:rating'].label <= maxRating) {
              return entry;
            } else {
              return null;
            }
          } else {
            // Voila, the first entry is the app info
            appName = entry['im:name'].label;
          }
        });

        // Alright, let's see if we've found some reviews
        if (reviews.length > 0) {
          // Woohoo, let's share some random review
          var randomIndex = Math.floor(Math.random() * (reviews.length - 0)) + 0;
          var randomReview = reviews[randomIndex];
          var randomReviewRating = randomReview['im:rating'].label;
          var randomReviewRatingStars = '';
          for (var i = 1; i <= 5; i++) {
            if (i <= randomReviewRating) {
              randomReviewRatingStars += '★';
            } else {
              randomReviewRatingStars += '☆';
            }
          }
          var randomReviewLabel = randomReview.content.label;
          var slackMessage = appName + '\n' + randomReviewRatingStars + ': ' + randomReviewLabel;
          successCallback(slackMessage);
        } else {
          var errorMessage = 'No reviews for app: ' + (appName ? appName : randomAppId);
          console.log(errorMessage);
          errorCallback(errorMessage);
        }
      }
    }
  );
};

var persistTeamSettings = function(teamDomain, appIdList, successCallback, errorCallback) {
  var TeamSettings = Parse.Object.extend('TeamSettings');
  var query = new Parse.Query(TeamSettings);
  query.equalTo('teamDomain', teamDomain);
  query.find({
    success: function(results) {
      // No settings yet, create a new entry
      if (results.length === 0) {
        var newTeamSettings = new TeamSettings();
        newTeamSettings.set('teamDomain', teamDomain);
        newTeamSettings.set('appIdList', appIdList);
        newTeamSettings.save(null, {
          success: function(persistedTeamSettings) {
            successCallback('Success! Your app IDs are persisted. From now on, use `/<your-slack-command>` to get a random review. For example: `/appreview`');
          },
          error: function(persistedTeamSettings, error) {
            // Execute any logic that should take place if the save fails.
            // error is a Parse.Error with an error code and message.
            console.log('Failed to create new object, with error code: ' + error.message);
            errorCallback('Failed to create new object, with error code: ' + error.message);
          }
        });
      // Settings available, update
      } else if (results.length === 1) {
        for (var index = 0; index < appIdList.length; index++) {
          var appId = appIdList[index];
          results[0].addUnique('appIdList', appId);
        }
        results[0].save();
        successCallback('Success! Your app IDs are persisted. From now on, use `/<your-slack-command>` to get a random review. For example: `/appreview`');
      // More than 1 settings entry for the given team... problem
      } else {
        console.log('More than 1 settings entry for team: ' + teamDomain);
        errorCallback('Something went wrong... Please try again');
      }
    },
    error: function(error) {
      console.log('Cannot load team settings for team: ' + teamDomain + '. Error: ' + error);
      errorCallback('Something went wrong... Please try again');
    }
  });
};

var listTeamSettings = function(teamDomain, successCallback, errorCallback) {
  // Load team settings
  var TeamSettings = Parse.Object.extend('TeamSettings');
  var query = new Parse.Query(TeamSettings);
  query.equalTo('teamDomain', teamDomain);
  query.find({
    success: function(results) {
      if (results.length === 0) {
        successCallback('We don\'t yet have any app IDs for your team. Please add some app IDs from iTunes Connect like so: `/<your-slack-command> add <comma separated app ID list>`. For example: `/appreview add 123,456`');
      } else if (results.length === 1) {
        var appIdArray = results[0].get('appIdList');
        var message = _.reduce(appIdArray, function(result, appId) {
          return result + '\n' + appId;
        });
        successCallback('Your team has the following app IDs configured: ' + message);
      } else {
        console.log('0 or more than 1 settings entry for team: ' + teamDomain);
        errorCallback('Something went wrong... Please try again');
      }
    },
    error: function(error) {
      console.log('Cannot load team settings for team: ' + teamDomain + '. Error: ' + error);
      errorCallback('Something went wrong... Please try again');
    }
  });
};

var setTeamSettingsConfigValue = function(teamDomain, configKey, configValue, successCallback, errorCallback) {
  var TeamSettings = Parse.Object.extend('TeamSettings');
  var query = new Parse.Query(TeamSettings);
  query.equalTo('teamDomain', teamDomain);
  query.find({
    success: function(results) {
      // No settings yet, create a new entry
      if (results.length === 0) {
        var newTeamSettings = new TeamSettings();
        newTeamSettings.set('teamDomain', teamDomain);
        newTeamSettings.set('appIdList', []);
        if (_.contains(configKeyWhitelist, configKey)) {
          newTeamSettings.set(configKey, configValue);
        }
        newTeamSettings.save(null, {
          success: function(persistedTeamSettings) {
            successCallback('Success! Your settings are persisted.');
          },
          error: function(persistedTeamSettings, error) {
            // Execute any logic that should take place if the save fails.
            // error is a Parse.Error with an error code and message.
            console.log('Failed to create new object, with error code: ' + error.message);
            errorCallback('Failed to create new object, with error code: ' + error.message);
          }
        });
      // Settings available, update
      } else if (results.length === 1) {
        if (_.contains(configKeyWhitelist, configKey)) {
          results[0].set(configKey, configValue);
        }
        results[0].save();
        successCallback('Success! Your settings are persisted.');
      // More than 1 settings entry for the given team... problem
      } else {
        console.log('More than 1 settings entry for team: ' + teamDomain);
        errorCallback('Something went wrong... Please try again');
      }
    },
    error: function(error) {
      console.log('Cannot load team settings for team: ' + teamDomain + '. Error: ' + error);
      errorCallback('Something went wrong... Please try again');
    }
  });
};

var processCommand = function(slackCommand, teamDomain, parameters, successCallback, errorCallback) {
  var parametersArray = parameters.split(' ');
  var command = parametersArray[0];
  if (command === 'add') {
    var appIdList = parametersArray[1].split(',');
    persistTeamSettings(teamDomain, appIdList, successCallback, errorCallback);
  } else if (command === 'list') {
    listTeamSettings(teamDomain, successCallback, errorCallback);
  } else if (command === 'set') {
    var configKey = parametersArray[1].split('=')[0];
    var configValue = parametersArray[1].split('=')[1];
    setTeamSettingsConfigValue(teamDomain, configKey, configValue, successCallback, errorCallback);
  } else if (command === 'help') {
    var helpMessage = 'Welcome to `slack-app-reviews`!\n\n' +
      'Usage: `' + slackCommand + ' <command>`\n\n' +
      'where `<command>` is one of:\n' +
      '    `add`, `list`, `set`, `help`\n\n' +
      '`' + slackCommand + ' add <list of app IDs>    ` A comma separated list of app IDs from iTunes Connect\n' +
      '`' + slackCommand + ' list                     ` Lists all configured app IDs\n' +
      '`' + slackCommand + ' set <configKey>=<value>  ` where `<configKey>` is `minRating` or `maxRating`. A value between 1 and 5, inclusive\n' +
      '`' + slackCommand + ' help                     ` Help\n';
    successCallback(helpMessage);
  }
  // TODO: Add more commands: 'reset', 'remove'
};

var sendSlackResponse = function(res, message) {
  res.json({
    response_type: 'in_channel',
    text: message
  });
};

var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
  extended: false
}));

app.post('/app-review', function(req, res) {
  var teamDomain = req.body.team_domain;
  var user = req.body.user_name;
  var slackCommand = req.body.command;
  var parameters = req.body.text;
  console.log('Team: ' + teamDomain + '; user: ' + user + '; Slack command: ' + slackCommand + '; parameters: ' + parameters);

  // Load team settings
  var TeamSettings = Parse.Object.extend('TeamSettings');
  var query = new Parse.Query(TeamSettings);
  query.equalTo('teamDomain', teamDomain);
  query.find({
    success: function(results) {
      // No team settings persisted yet
      if (results.length === 0) {
        // If parameters were provided, process them
        if (parameters && parameters.length > 0) {
          processCommand(slackCommand, teamDomain, parameters, function(message) {
            sendSlackResponse(res, message);
          }, function(error) {
            sendSlackResponse(res, error);
          });
        } else {
          console.log('No command provided');
          sendSlackResponse(res, 'Please provide a command, such as `/appreview add 123,456,789`');
        }
      // Exactly one team settings row - perfect
      } else if (results.length === 1) {
        // If parameters were provided, process them
        if (parameters && parameters.length > 0) {
          processCommand(slackCommand, teamDomain, parameters, function(message) {
            sendSlackResponse(res, message);
          }, function(error) {
            sendSlackResponse(res, error);
          });
        // If no paramters were provided, load a review
        } else {
          var teamSettings = results[0];
          var appIdList = teamSettings.get('appIdList');
          if (appIdList && appIdList.length === 0) {
            // No settings yet for the given team domain
            sendSlackResponse(res, 'Hey there ' + user + '! We don\'t yet have any app IDs for your team. Please add some app IDs from iTunes Connect like so: `/<your-slack-command> add <comma separated app ID list>`. For example: `/appreview add 123,456`');
          } else {
            loadReviewFromItunes(teamSettings, function(message) {
              sendSlackResponse(res, message);
            }, function(error) {
              sendSlackResponse(res, error);
            });
          }
        }
      } else {
        console.log('More than 1 settings entry for team: ' + teamDomain);
        sendSlackResponse(res, 'Hey there ' + user + '! Something went wrong... Please try again');
      }
    },
    error: function(error) {
      console.log('Cannot load team settings for team: ' + teamDomain + '. Error: ' + error);
      sendSlackResponse(res, 'Hey there ' + user + '! Something went wrong... Please try again');
    }
  });
});

var port = process.env.PORT || 3000;
var server = app.listen(port, function() {
  Parse.initialize(process.env.PARSE_APP_ID, process.env.PARSE_APP_KEY);

  var host = server.address().address;
  var port = server.address().port;

  console.log('Example app listening at http://%s:%s', host, port);
});
<commit_msg>Sort list result of app IDs<commit_after>var _ = require('lodash');
var request = require('request');
var express = require('express');
var bodyParser = require('body-parser');
var Parse = require('parse/node');
var config = require('./config.json');
var configKeyWhitelist = ['minRating', 'maxRating'];

var loadReviewFromItunes = function(teamSettings, successCallback, errorCallback) {
  var appIdList = teamSettings.get('appIdList');
  var minRating = teamSettings.get('minRating') || 1;
  var maxRating = teamSettings.get('maxRating') || 5;
  var randomAppIndex = Math.floor(Math.random() * (appIdList.length));
  var randomAppId = appIdList[randomAppIndex];
  // Query iTunes
  request(config.itunesApi.baseUrl + randomAppId + '/' + config.itunesApi.responseFormat,
    function(error, response, body) {
      if (!error && response.statusCode == 200) {
        var appName;
        var entries = JSON.parse(body).feed.entry;
        var reviews = _.filter(entries, function(entry) {
          if (entry['im:rating']) {
            // All but the first entry have that property.
            if (entry['im:rating'].label >= minRating && entry['im:rating'].label <= maxRating) {
              return entry;
            } else {
              return null;
            }
          } else {
            // Voila, the first entry is the app info
            appName = entry['im:name'].label;
          }
        });

        // Alright, let's see if we've found some reviews
        if (reviews.length > 0) {
          // Woohoo, let's share some random review
          var randomIndex = Math.floor(Math.random() * (reviews.length - 0)) + 0;
          var randomReview = reviews[randomIndex];
          var randomReviewRating = randomReview['im:rating'].label;
          var randomReviewRatingStars = '';
          for (var i = 1; i <= 5; i++) {
            if (i <= randomReviewRating) {
              randomReviewRatingStars += '★';
            } else {
              randomReviewRatingStars += '☆';
            }
          }
          var randomReviewLabel = randomReview.content.label;
          var slackMessage = appName + '\n' + randomReviewRatingStars + ': ' + randomReviewLabel;
          successCallback(slackMessage);
        } else {
          var errorMessage = 'No reviews for app: ' + (appName ? appName : randomAppId);
          console.log(errorMessage);
          errorCallback(errorMessage);
        }
      }
    }
  );
};

var persistTeamSettings = function(teamDomain, appIdList, successCallback, errorCallback) {
  var TeamSettings = Parse.Object.extend('TeamSettings');
  var query = new Parse.Query(TeamSettings);
  query.equalTo('teamDomain', teamDomain);
  query.find({
    success: function(results) {
      // No settings yet, create a new entry
      if (results.length === 0) {
        var newTeamSettings = new TeamSettings();
        newTeamSettings.set('teamDomain', teamDomain);
        newTeamSettings.set('appIdList', appIdList);
        newTeamSettings.save(null, {
          success: function(persistedTeamSettings) {
            successCallback('Success! Your app IDs are persisted. From now on, use `/<your-slack-command>` to get a random review. For example: `/appreview`');
          },
          error: function(persistedTeamSettings, error) {
            // Execute any logic that should take place if the save fails.
            // error is a Parse.Error with an error code and message.
            console.log('Failed to create new object, with error code: ' + error.message);
            errorCallback('Failed to create new object, with error code: ' + error.message);
          }
        });
      // Settings available, update
      } else if (results.length === 1) {
        for (var index = 0; index < appIdList.length; index++) {
          var appId = appIdList[index];
          results[0].addUnique('appIdList', appId);
        }
        results[0].save();
        successCallback('Success! Your app IDs are persisted. From now on, use `/<your-slack-command>` to get a random review. For example: `/appreview`');
      // More than 1 settings entry for the given team... problem
      } else {
        console.log('More than 1 settings entry for team: ' + teamDomain);
        errorCallback('Something went wrong... Please try again');
      }
    },
    error: function(error) {
      console.log('Cannot load team settings for team: ' + teamDomain + '. Error: ' + error);
      errorCallback('Something went wrong... Please try again');
    }
  });
};

var listTeamSettings = function(teamDomain, successCallback, errorCallback) {
  // Load team settings
  var TeamSettings = Parse.Object.extend('TeamSettings');
  var query = new Parse.Query(TeamSettings);
  query.equalTo('teamDomain', teamDomain);
  query.find({
    success: function(results) {
      if (results.length === 0) {
        successCallback('We don\'t yet have any app IDs for your team. Please add some app IDs from iTunes Connect like so: `/<your-slack-command> add <comma separated app ID list>`. For example: `/appreview add 123,456`');
      } else if (results.length === 1) {
        var appIdArray = _.sortBy(results[0].get('appIdList'));
        var message = _.reduce(appIdArray, function(result, appId) {
          return result + '\n' + appId;
        });
        successCallback('Your team has the following app IDs configured:\n' + message);
      } else {
        console.log('0 or more than 1 settings entry for team: ' + teamDomain);
        errorCallback('Something went wrong... Please try again');
      }
    },
    error: function(error) {
      console.log('Cannot load team settings for team: ' + teamDomain + '. Error: ' + error);
      errorCallback('Something went wrong... Please try again');
    }
  });
};

var setTeamSettingsConfigValue = function(teamDomain, configKey, configValue, successCallback, errorCallback) {
  var TeamSettings = Parse.Object.extend('TeamSettings');
  var query = new Parse.Query(TeamSettings);
  query.equalTo('teamDomain', teamDomain);
  query.find({
    success: function(results) {
      // No settings yet, create a new entry
      if (results.length === 0) {
        var newTeamSettings = new TeamSettings();
        newTeamSettings.set('teamDomain', teamDomain);
        newTeamSettings.set('appIdList', []);
        if (_.contains(configKeyWhitelist, configKey)) {
          newTeamSettings.set(configKey, configValue);
        }
        newTeamSettings.save(null, {
          success: function(persistedTeamSettings) {
            successCallback('Success! Your settings are persisted.');
          },
          error: function(persistedTeamSettings, error) {
            // Execute any logic that should take place if the save fails.
            // error is a Parse.Error with an error code and message.
            console.log('Failed to create new object, with error code: ' + error.message);
            errorCallback('Failed to create new object, with error code: ' + error.message);
          }
        });
      // Settings available, update
      } else if (results.length === 1) {
        if (_.contains(configKeyWhitelist, configKey)) {
          results[0].set(configKey, configValue);
        }
        results[0].save();
        successCallback('Success! Your settings are persisted.');
      // More than 1 settings entry for the given team... problem
      } else {
        console.log('More than 1 settings entry for team: ' + teamDomain);
        errorCallback('Something went wrong... Please try again');
      }
    },
    error: function(error) {
      console.log('Cannot load team settings for team: ' + teamDomain + '. Error: ' + error);
      errorCallback('Something went wrong... Please try again');
    }
  });
};

var processCommand = function(slackCommand, teamDomain, parameters, successCallback, errorCallback) {
  var parametersArray = parameters.split(' ');
  var command = parametersArray[0];
  if (command === 'add') {
    var appIdList = parametersArray[1].split(',');
    persistTeamSettings(teamDomain, appIdList, successCallback, errorCallback);
  } else if (command === 'list') {
    listTeamSettings(teamDomain, successCallback, errorCallback);
  } else if (command === 'set') {
    var configKey = parametersArray[1].split('=')[0];
    var configValue = parametersArray[1].split('=')[1];
    setTeamSettingsConfigValue(teamDomain, configKey, configValue, successCallback, errorCallback);
  } else if (command === 'help') {
    var helpMessage = 'Welcome to `slack-app-reviews`!\n\n' +
      'Usage: `' + slackCommand + ' <command>`\n\n' +
      'where `<command>` is one of:\n' +
      '    `add`, `list`, `set`, `help`\n\n' +
      '`' + slackCommand + ' add <list of app IDs>    ` A comma separated list of app IDs from iTunes Connect\n' +
      '`' + slackCommand + ' list                     ` Lists all configured app IDs\n' +
      '`' + slackCommand + ' set <configKey>=<value>  ` where `<configKey>` is `minRating` or `maxRating`. A value between 1 and 5, inclusive\n' +
      '`' + slackCommand + ' help                     ` Help\n';
    successCallback(helpMessage);
  }
  // TODO: Add more commands: 'reset', 'remove'
};

var sendSlackResponse = function(res, message) {
  res.json({
    response_type: 'in_channel',
    text: message
  });
};

var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
  extended: false
}));

app.post('/app-review', function(req, res) {
  var teamDomain = req.body.team_domain;
  var user = req.body.user_name;
  var slackCommand = req.body.command;
  var parameters = req.body.text;
  console.log('Team: ' + teamDomain + '; user: ' + user + '; Slack command: ' + slackCommand + '; parameters: ' + parameters);

  // Load team settings
  var TeamSettings = Parse.Object.extend('TeamSettings');
  var query = new Parse.Query(TeamSettings);
  query.equalTo('teamDomain', teamDomain);
  query.find({
    success: function(results) {
      // No team settings persisted yet
      if (results.length === 0) {
        // If parameters were provided, process them
        if (parameters && parameters.length > 0) {
          processCommand(slackCommand, teamDomain, parameters, function(message) {
            sendSlackResponse(res, message);
          }, function(error) {
            sendSlackResponse(res, error);
          });
        } else {
          console.log('No command provided');
          sendSlackResponse(res, 'Please provide a command, such as `/appreview add 123,456,789`');
        }
      // Exactly one team settings row - perfect
      } else if (results.length === 1) {
        // If parameters were provided, process them
        if (parameters && parameters.length > 0) {
          processCommand(slackCommand, teamDomain, parameters, function(message) {
            sendSlackResponse(res, message);
          }, function(error) {
            sendSlackResponse(res, error);
          });
        // If no paramters were provided, load a review
        } else {
          var teamSettings = results[0];
          var appIdList = teamSettings.get('appIdList');
          if (appIdList && appIdList.length === 0) {
            // No settings yet for the given team domain
            sendSlackResponse(res, 'Hey there ' + user + '! We don\'t yet have any app IDs for your team. Please add some app IDs from iTunes Connect like so: `/<your-slack-command> add <comma separated app ID list>`. For example: `/appreview add 123,456`');
          } else {
            loadReviewFromItunes(teamSettings, function(message) {
              sendSlackResponse(res, message);
            }, function(error) {
              sendSlackResponse(res, error);
            });
          }
        }
      } else {
        console.log('More than 1 settings entry for team: ' + teamDomain);
        sendSlackResponse(res, 'Hey there ' + user + '! Something went wrong... Please try again');
      }
    },
    error: function(error) {
      console.log('Cannot load team settings for team: ' + teamDomain + '. Error: ' + error);
      sendSlackResponse(res, 'Hey there ' + user + '! Something went wrong... Please try again');
    }
  });
});

var port = process.env.PORT || 3000;
var server = app.listen(port, function() {
  Parse.initialize(process.env.PARSE_APP_ID, process.env.PARSE_APP_KEY);

  var host = server.address().address;
  var port = server.address().port;

  console.log('Example app listening at http://%s:%s', host, port);
});
<|endoftext|>


<commit_before>"use strict";

var EventEmitter  = require('events').EventEmitter,
    path          = require('path'),
    q             = require('kew'),
    utils         = require('lodash'),
    resolve       = require('browser-resolve'),
    builtins      = require('browser-builtins'),
    aggregate     = require('stream-aggregate-promise'),
    DGraph        = require('dgraph').Graph,
    watchGraph    = require('dgraph-live'),
    cssImportTr   = require('dgraph-css-import'),
    cssBundler    = require('./bundlers/css'),
    jsBundler     = require('./bundlers/js'),
    common        = require('./common');

/**
 * Compose bundle
 *
 * @param {Array.<String|Module>} entries
 * @param {Options} opts
 */
function Composer(entries, opts) {
  opts = opts || {};

  this.entries = [];

  this.opts = opts;
  this.basedir = opts.basedir || process.cwd();

  this._entries = utils.memoize(this._entries);
  this._graph = utils.memoize(this._graph);
  this._graphIndex = utils.memoize(this._graphIndex);

  [].concat(entries)
    .filter(Boolean)
    .forEach(this._addEntry.bind(this));
}

utils.assign(Composer.prototype, EventEmitter.prototype, {

  /**
   * Add an entry module
   *
   * @param {Module|String} entry
   * @private
   */
  _addEntry: function(entry) {
    if (utils.isString(entry))
      entry = {id: entry};

    if (utils.isBoolean(entry.expose))
      entry.expose = entry.id;

    this.entries.push(entry);
  },

  /**
   * Resolve a single module
   *
   * @param {Module} mod
   * @private
   */
  _resolve: function(mod) {
    var promise = q.defer(),
        parent = {filename: path.join(mod.basedir || this.basedir, '_fake.js')};
    resolve(mod.id, parent, promise.makeNodeResolver());
    return promise.then(function(id) {
      return utils.assign(mod, {id: id});
    });
  },

  /**
   * Get resolved entries
   *
   * @private
   */
  _entries: function() {
    return q.all(this.entries.map(this._resolve.bind(this)));
  },

  /**
   * Mark composer as updated
   *
   * @private
   */
  _updated: function() {
    this._graphIndex.cache = {};
    this.emit('update');
  },

  /**
   * Create a depenency graph
   *
   * @private
   */
  _graph: function() {
    return this._entries().then(function(entries) {
      var graph = new DGraph(entries, {
          transform: [].concat(this.opts.transform, cssImportTr),
          extensions: this.opts.extensions,
          modules: builtins
        });

      if (this.opts.debug) {
        graph = watchGraph(graph);
        graph.on('update', this._updated.bind(this));
      }

      return graph;
    }.bind(this));
  },

  /**
   * Aggregate a depenency graph into a graph index
   *
   * @private
   */
  _graphIndex: function() {
    return this._graph()
      .then(function(graph) { return aggregate(graph.toStream()); })
      .then(common.buildIndex);
  },

  /**
   * Separate graph into JS and CSS subgraphs
   *
   * @private
   */
  _separatedGraph: function(graph) {
    return this._graphIndex().then(function(graph) {
      var js = utils.clone(graph),
          css = common.separateSubgraph(js, common.isCSS);
      return {
        js: common.stubMissingDeps(js),
        css: common.stubMissingDeps(css)
      };
    }.bind(this));
  },

  _bundleCSS: function(graph) {
    return cssBundler(graph);
  },

  _bundleJS: function(graph) {
    return jsBundler(graph, {
      debug: this.opts.debug,
      expose: common.exposeMap(this.entries)
    });
  },

  /**
   * Bundle
   */
  all: function(cb) {
    var streams = this._separatedGraph().then(function(graph) {
      var bundles = {},
          name = path.basename(this.entries[0].id).replace(/\..*$/, '');
      bundles[name + '.bundle.css'] = this._bundleCSS(graph.css);
      bundles[name + '.bundle.js'] = this._bundleJS(graph.js);
      return bundles;
    }.bind(this));

    common.thenCallback(streams, cb);
    return streams;
  },

  js: function(cb) {
    var stream = this._separatedGraph().then(function(graph) {
      return this._bundleJS(graph.js);
    }.bind(this));

    common.thenCallback(stream, cb);

    return stream;
  },

  css: function(cb) {
    var stream = this._separatedGraph().then(function(graph) {
      return this._bundleCSS(graph.css);
    }.bind(this));

    common.thenCallback(stream, cb);

    return stream;
  }
});

module.exports = function(entries, opts) {
  return new Composer(entries, opts);
}
module.exports.Composer = Composer;
<commit_msg>emit filename of a changed file with update event<commit_after>"use strict";

var EventEmitter  = require('events').EventEmitter,
    path          = require('path'),
    q             = require('kew'),
    utils         = require('lodash'),
    resolve       = require('browser-resolve'),
    builtins      = require('browser-builtins'),
    aggregate     = require('stream-aggregate-promise'),
    DGraph        = require('dgraph').Graph,
    watchGraph    = require('dgraph-live'),
    cssImportTr   = require('dgraph-css-import'),
    cssBundler    = require('./bundlers/css'),
    jsBundler     = require('./bundlers/js'),
    common        = require('./common');

/**
 * Compose bundle
 *
 * @param {Array.<String|Module>} entries
 * @param {Options} opts
 */
function Composer(entries, opts) {
  opts = opts || {};

  this.entries = [];

  this.opts = opts;
  this.basedir = opts.basedir || process.cwd();

  this._entries = utils.memoize(this._entries);
  this._graph = utils.memoize(this._graph);
  this._graphIndex = utils.memoize(this._graphIndex);

  [].concat(entries)
    .filter(Boolean)
    .forEach(this._addEntry.bind(this));
}

utils.assign(Composer.prototype, EventEmitter.prototype, {

  /**
   * Add an entry module
   *
   * @param {Module|String} entry
   * @private
   */
  _addEntry: function(entry) {
    if (utils.isString(entry))
      entry = {id: entry};

    if (utils.isBoolean(entry.expose))
      entry.expose = entry.id;

    this.entries.push(entry);
  },

  /**
   * Resolve a single module
   *
   * @param {Module} mod
   * @private
   */
  _resolve: function(mod) {
    var promise = q.defer(),
        parent = {filename: path.join(mod.basedir || this.basedir, '_fake.js')};
    resolve(mod.id, parent, promise.makeNodeResolver());
    return promise.then(function(id) {
      return utils.assign(mod, {id: id});
    });
  },

  /**
   * Get resolved entries
   *
   * @private
   */
  _entries: function() {
    return q.all(this.entries.map(this._resolve.bind(this)));
  },

  /**
   * Mark composer as updated
   *
   * @private
   */
  _updated: function(filename) {
    this._graphIndex.cache = {};
    this.emit('update', filename);
  },

  /**
   * Create a depenency graph
   *
   * @private
   */
  _graph: function() {
    return this._entries().then(function(entries) {
      var graph = new DGraph(entries, {
          transform: [].concat(this.opts.transform, cssImportTr),
          extensions: this.opts.extensions,
          modules: builtins
        });

      if (this.opts.debug) {
        graph = watchGraph(graph);
        graph.on('update', this._updated.bind(this));
      }

      return graph;
    }.bind(this));
  },

  /**
   * Aggregate a depenency graph into a graph index
   *
   * @private
   */
  _graphIndex: function() {
    return this._graph()
      .then(function(graph) { return aggregate(graph.toStream()); })
      .then(common.buildIndex);
  },

  /**
   * Separate graph into JS and CSS subgraphs
   *
   * @private
   */
  _separatedGraph: function(graph) {
    return this._graphIndex().then(function(graph) {
      var js = utils.clone(graph),
          css = common.separateSubgraph(js, common.isCSS);
      return {
        js: common.stubMissingDeps(js),
        css: common.stubMissingDeps(css)
      };
    }.bind(this));
  },

  _bundleCSS: function(graph) {
    return cssBundler(graph);
  },

  _bundleJS: function(graph) {
    return jsBundler(graph, {
      debug: this.opts.debug,
      expose: common.exposeMap(this.entries)
    });
  },

  /**
   * Bundle
   */
  all: function(cb) {
    var streams = this._separatedGraph().then(function(graph) {
      var bundles = {},
          name = path.basename(this.entries[0].id).replace(/\..*$/, '');
      bundles[name + '.bundle.css'] = this._bundleCSS(graph.css);
      bundles[name + '.bundle.js'] = this._bundleJS(graph.js);
      return bundles;
    }.bind(this));

    common.thenCallback(streams, cb);
    return streams;
  },

  js: function(cb) {
    var stream = this._separatedGraph().then(function(graph) {
      return this._bundleJS(graph.js);
    }.bind(this));

    common.thenCallback(stream, cb);

    return stream;
  },

  css: function(cb) {
    var stream = this._separatedGraph().then(function(graph) {
      return this._bundleCSS(graph.css);
    }.bind(this));

    common.thenCallback(stream, cb);

    return stream;
  }
});

module.exports = function(entries, opts) {
  return new Composer(entries, opts);
}
module.exports.Composer = Composer;
<|endoftext|>


<commit_before>var _ = require("lodash");
var request = require('request');
var Dice = require("./dice");
var koa = require('koa');
var koaBody = require('koa-body');
var koaRouter = require('koa-router');

var app = koa();
app.use(koaBody());

var router = koaRouter();
var advertisement = process.env.AD ||
    'Thanks for being a part of RPG Talk! If you\`d like to help support development for the community, ' +
    'become a patron at https://www.patreon.com/rpg_talk.';
var skip = JSON.parse(process.env.SKIP_AD || '[]');

router.post('/', function *() {
    var user = this.request.body.user_name;

    var dice = new Dice(this.request.body.text);
    dice.execute();

    var result = dice.result();
    var rolls = dice.rolls.map((die) => die.result);
    response = rolls + ' = ' + result;

    this.body = {
        response_type: 'in_channel',
        text: response
    };

    if (!_.contains(skip, user)) {
        request.post(this.request.body.response_url, {
            text: advertisement
        });
    }
});

app.use(router.routes());
app.use(router.allowedMethods());

app.listen((process.env.PORT || 5000));<commit_msg>Fix includes<commit_after>var _ = require("lodash");
var request = require('request');
var Dice = require("./dice");
var koa = require('koa');
var koaBody = require('koa-body');
var koaRouter = require('koa-router');

var app = koa();
app.use(koaBody());

var router = koaRouter();
var advertisement = process.env.AD ||
    'Thanks for being a part of RPG Talk! If you\`d like to help support development for the community, ' +
    'become a patron at https://www.patreon.com/rpg_talk.';
var skip = JSON.parse(process.env.SKIP_AD || '[]');

router.post('/', function *() {
    var user = this.request.body.user_name;

    var dice = new Dice(this.request.body.text);
    dice.execute();

    var result = dice.result();
    var rolls = dice.rolls.map((die) => die.result);
    response = rolls + ' = ' + result;

    this.body = {
        response_type: 'in_channel',
        text: response
    };

    if (!_.includes(skip, user)) {
        request.post(this.request.body.response_url, {
            text: advertisement
        });
    }
});

app.use(router.routes());
app.use(router.allowedMethods());

app.listen((process.env.PORT || 5000));<|endoftext|>


<commit_before>var scripty = require('azure-scripty');
var console = require('better-console');
var _ = require('lodash');
var util = require('./util');
var async = require('async');
var path = require('path')
var Q = require('q');
var config = require('./config');
var os = require('os');

var qAzureInvoke = Q.denodeify(scripty.invoke)

function nodeTest(a, b, callback) {
  callback(a, b);
}

function ensureCreateResourceGroupExists(resourceGroupName, location) {
  console.log('Checking if resourceGroup', resourceGroupName, 'exists')
  var showCmd = {
    command: 'group show',
    positional: [resourceGroupName],
  };

  var createCmd = {
    command: 'group create',
    name: resourceGroupName,
    location: '"' + location + '"'
  };

  return qAzureInvoke(showCmd)
    .then(function (response) {
      console.log(resourceGroupName, ' exists')
    })
    .catch(function (err) {
      console.error(err);
      console.log(resourceGroupName, ' does not exists. Creating one')
      return qAzureInvoke(createCmd)
        .then(function (response) {
          if (_.isString(response) && response.indexOf('"Succeeded"')) {
            console.log('ResourceGroup creation succeeded.');
          }
          else {
            throw Error('ResourceGroup failed.')
          }
        }
          )
        .catch(function (err, response) {
          console.log('ResourceGroup creation completed with', response);
          // parsing error could happen even when creation is successful
          if (response && response.indexOf('"Succeeded"')) {
            console.log('ResourceGroup creation succeeded.');
          }
          else {
            throw Error('ResourceGroup failed.')
          }
        })

    })
}

function escapeParamsString(paramString) {
  if (os.platform() === 'win32') {
    return '"' + paramString.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"';
  }
  else {
    // use single quotes on mac otherwise mac bash would expand things like !
    return "'" + paramString.replace(/\\/g, '\\\\').replace(/'/g, "\\'") + "'";
  }
}

function invokeAzureDeployment(templatePath, params, name, config) {
  console.log('Creating ' + name);
  templatePath
  var currentdeploymentName = config.deploymentBaseName + name;

  var cmd = {
    command: 'group deployment create',
    name: currentdeploymentName,
    parameters: escapeParamsString(JSON.stringify(params)),
    // parameters: "'" + JSON.stringify(params) + "'",
    short:
    {
      g: config.resourceGroup,
      f: '"' + templatePath + '"'
    }
  };

  return qAzureInvoke(cmd)
    .then(function (response) {
      console.log(name + ' deployed successfully');
      return response;
    })
    .catch(function (err, response) {
      var timeout = 10000;
      console.error('Deploy failed with', err, response, 'Wait for', timeout, 'ms to retrieve deployment log (Azure needs some time):');
      setTimeout(function () {
        util.showDeploymentLog(config.resourceGroup, currentdeploymentName)
      }, timeout);
    });
}

function deploySql(config, params) {
  return invokeAzureDeployment(
    path.resolve(__dirname, 'arm', 'sql', 'azuredeploy.json'),
    params,
    'sql',
    config
    )
}

function deployWebapp(config, params) {
  return invokeAzureDeployment(
    path.resolve(__dirname, 'arm', 'webapp', 'azuredeploy.json'),
    params,
    'webapp',
    config
    )
}

function setKeyVault(vaultName, keyName, value) {
  return qAzureInvoke(
    {
      command: "keyvault secret set",
      short:
      {
        u: vaultName,
        s: keyName
      },
      value: escapeParamsString(value)
    }
    )
}

// will remove once website is loading from secrete store
var sqlConn;

function go() {
  qAzureInvoke(
    "config mode arm"
    ).then(function (response) {
      return ensureCreateResourceGroupExists(config.resourceGroup, config.location)
    })
    .then(function (response) {
      return deploySql(config, config.sql)
    }
      )
    .then(function (response) {
      // FQDN should come from azure cli output, but it has problem returnning valid json output, https://github.com/Azure/azure-xplat-cli/issues/2049
      // So let's concat ourselves first wayliutododev.database.windows.net
      var sqlFQDN = config.sql.sqlServerName.value + '.database.windows.net';

      // now the sql connection
      sqlConn = 'Data Source=tcp:' + sqlFQDN
      + ',1433;Initial Catalog=' + config.sql.sqlDbName.value
      + ';User Id=' + config.sql.sqlServerAdminLogin.value
      + '@' + config.sql.sqlServerName.value
      + ';Password=' + config.sql.sqlServerAdminPassword.value + ';';

      console.log('Setting sqlConnection to Keyvault:', config.keyVault.vaultName, 'keyName:', config.appName);
      return setKeyVault(config.keyVault.vaultName, config.appName, sqlConn)
    })
    .then(function (response) {
      console.log('KeyVault updated successfully, now setting keyVault uri to webapp.');
      config.webapp.secretUri.value = response.id
      // reuse the external sqlConn for now
      config.webapp.sqlConn.value = sqlConn;
      return deployWebapp(config, config.webapp)
    })
    .catch(function (err) {
      console.error(err)
    })
    .done(function (response) {
      console.log('Completed')
    })
}

module.exports.start = function (options) {
  go();
}
<commit_msg>show response<commit_after>var scripty = require('azure-scripty');
var console = require('better-console');
var _ = require('lodash');
var util = require('./util');
var async = require('async');
var path = require('path')
var Q = require('q');
var config = require('./config');
var os = require('os');

var qAzureInvoke = Q.denodeify(scripty.invoke)

function nodeTest(a, b, callback) {
  callback(a, b);
}

function ensureCreateResourceGroupExists(resourceGroupName, location) {
  console.log('Checking if resourceGroup', resourceGroupName, 'exists')
  var showCmd = {
    command: 'group show',
    positional: [resourceGroupName],
  };

  var createCmd = {
    command: 'group create',
    name: resourceGroupName,
    location: '"' + location + '"'
  };

  return qAzureInvoke(showCmd)
    .then(function (response) {
      console.log(resourceGroupName, ' exists')
    })
    .catch(function (err) {
      console.error(err);
      console.log(resourceGroupName, ' does not exists. Creating one')
      return qAzureInvoke(createCmd)
        .then(function (response) {
          if (_.isString(response) && response.indexOf('"Succeeded"')) {
            console.log('ResourceGroup creation succeeded.');
          }
          else {
            throw Error('ResourceGroup failed.')
          }
        }
          )
        .catch(function (err, response) {
          console.log('ResourceGroup creation completed with', response);
          // parsing error could happen even when creation is successful
          if (response && response.indexOf('"Succeeded"')) {
            console.log('ResourceGroup creation succeeded.');
          }
          else {
            throw Error('ResourceGroup failed.')
          }
        })

    })
}

function escapeParamsString(paramString) {
  if (os.platform() === 'win32') {
    return '"' + paramString.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"';
  }
  else {
    // use single quotes on mac otherwise mac bash would expand things like !
    return "'" + paramString.replace(/\\/g, '\\\\').replace(/'/g, "\\'") + "'";
  }
}

function invokeAzureDeployment(templatePath, params, name, config) {
  console.log('Creating ' + name);
  templatePath
  var currentdeploymentName = config.deploymentBaseName + name;

  var cmd = {
    command: 'group deployment create',
    name: currentdeploymentName,
    parameters: escapeParamsString(JSON.stringify(params)),
    // parameters: "'" + JSON.stringify(params) + "'",
    short:
    {
      g: config.resourceGroup,
      f: '"' + templatePath + '"'
    }
  };

  return qAzureInvoke(cmd)
    .then(function (response) {
      console.log(name + ' deployed successfully');
      return response;
    })
    .catch(function (err, response) {
      var timeout = 10000;
      console.error('Deploy failed with', err, response, 'Wait for', timeout, 'ms to retrieve deployment log (Azure needs some time):');
      setTimeout(function () {
        util.showDeploymentLog(config.resourceGroup, currentdeploymentName)
      }, timeout);
    });
}

function deploySql(config, params) {
  return invokeAzureDeployment(
    path.resolve(__dirname, 'arm', 'sql', 'azuredeploy.json'),
    params,
    'sql',
    config
    )
}

function deployWebapp(config, params) {
  return invokeAzureDeployment(
    path.resolve(__dirname, 'arm', 'webapp', 'azuredeploy.json'),
    params,
    'webapp',
    config
    )
}

function setKeyVault(vaultName, keyName, value) {
  return qAzureInvoke(
    {
      command: "keyvault secret set",
      short:
      {
        u: vaultName,
        s: keyName
      },
      value: escapeParamsString(value)
    }
    )
}

// will remove once website is loading from secrete store
var sqlConn;

function go() {
  qAzureInvoke(
    "config mode arm"
    ).then(function (response) {
      return ensureCreateResourceGroupExists(config.resourceGroup, config.location)
    })
    .then(function (response) {
      return deploySql(config, config.sql)
    }
      )
    .then(function (response) {
      // FQDN should come from azure cli output, but it has problem returnning valid json output, https://github.com/Azure/azure-xplat-cli/issues/2049
      // So let's concat ourselves first wayliutododev.database.windows.net
      var sqlFQDN = config.sql.sqlServerName.value + '.database.windows.net';

      // now the sql connection
      sqlConn = 'Data Source=tcp:' + sqlFQDN
      + ',1433;Initial Catalog=' + config.sql.sqlDbName.value
      + ';User Id=' + config.sql.sqlServerAdminLogin.value
      + '@' + config.sql.sqlServerName.value
      + ';Password=' + config.sql.sqlServerAdminPassword.value + ';';

      console.log('Setting sqlConnection to Keyvault:', config.keyVault.vaultName, 'keyName:', config.appName);
      return setKeyVault(config.keyVault.vaultName, config.appName, sqlConn)
    })
    .then(function (response) {
      console.log('KeyVault updated successfully, now setting keyVault uri to webapp.');
      config.webapp.secretUri.value = response.id
      // reuse the external sqlConn for now
      config.webapp.sqlConn.value = sqlConn;
      return deployWebapp(config, config.webapp)
    })
    .catch(function (err) {
      console.error(err)
    })
    .done(function (response) {
      console.log(response, 'Provisioning Completed.')
    })
}

module.exports.start = function (options) {
  go();
}
<|endoftext|>


<commit_before>// List all imports
var RateLimiter = require('./lib/ratelimiter'),
	Limit = require('./lib/limit'),
	redis = require('redis');

// Create new limits
// l1 = daily limit of 50,000 calls across all users
// l2 = hourly limit of 10,000 calls across all users
// l3 = daily limit of 500 calls per user
// l4 = hourly limit of 100 calls per user
var l1 = new Limit("{sourceName}:global:daily", 86400, 50000),
	l2 = new Limit("{sourceName}:global:hourly", 3600, 200),
	l3 = new Limit("{sourceName}:{userID}:daily", 86400, 500),
	l4 = new Limit("{sourceName}:{userID}:hourly", 3600, 100);

// Create a client for Redis
var REDIS_PORT = 6379,
	REDIS_HOST = "127.0.0.1",
	redisClient = redis.createClient(REDIS_PORT, REDIS_HOST);

// Create a rate limiter and give as input the created limits and Redis client
var rl = new RateLimiter("fitbit", [l1,l2,l3,l4], redisClient);

// Send requests one after another for a single user
var requestDispatcher = function(i, NUMBER_OF_CALLS) {
	if (i < NUMBER_OF_CALLS) {
		rl.request('123456', function(err, res) {
			if (err)
				console.log("REQUEST NOT ALLOWED for user: " +
					err.uid + " | LIMIT(s) REACHED: " + err.reachedLimits);
			else
				console.log("REQUEST ALLOWED for user: " + res.uid);
			// Send the next request
			requestDispatcher(i+1, NUMBER_OF_CALLS);
		});
	}
};

// Send requests for two users one after another
var simultaneousRequestDispatcher = function(i, NUMBER_OF_CALLS) {

	if (i < NUMBER_OF_CALLS) {
		// If i is even, send request as user1, send it as user2 otherwise
		if (i % 2 == 0) {
			rl.request('user1', function(err, res) {
				if (err)
					console.log("REQUEST #" + (i+1) + " IS NOT ALLOWED for user: " +
						err.uid + " | LIMIT(s) REACHED: " + err.reachedLimits);
				else
					console.log("REQUEST #" + (i+1) + " IS ALLOWED for user: " + res.uid);
			});
		} else {
			rl.request('user2', function(err, res) {
				if (err)
					console.log("REQUEST #" + (i+1) + " IS NOT ALLOWED for user: " +
						err.uid + " | LIMIT(s) REACHED: " + err.reachedLimits);
				else
					console.log("REQUEST #"+ (i+1) + " IS ALLOWED for user: " + res.uid);
			});
		}
		// Send the next request
		simultaneousRequestDispatcher(i+1, NUMBER_OF_CALLS);
	}

};

// Start sending the requests
// requestDispatcher(0, 201);

simultaneousRequestDispatcher(0, 201);
<commit_msg>Fix dispatcher arguments<commit_after>// List all imports
var RateLimiter = require('./lib/ratelimiter'),
	Limit = require('./lib/limit'),
	redis = require('redis');

// Create new limits
// l1 = daily limit of 50,000 calls across all users
// l2 = hourly limit of 10,000 calls across all users
// l3 = daily limit of 500 calls per user
// l4 = hourly limit of 100 calls per user
var l1 = new Limit("{sourceName}:global:daily", 86400, 50000),
	l2 = new Limit("{sourceName}:global:hourly", 3600, 200),
	l3 = new Limit("{sourceName}:{userID}:daily", 86400, 500),
	l4 = new Limit("{sourceName}:{userID}:hourly", 3600, 100);

// Create a client for Redis
var REDIS_PORT = 6379,
	REDIS_HOST = "127.0.0.1",
	redisClient = redis.createClient(REDIS_PORT, REDIS_HOST);

// Create a rate limiter and give as input the created limits and Redis client
var rl = new RateLimiter("fitbit", [l1,l2,l3,l4], redisClient);

// Send requests one after another for a single user
var requestDispatcher = function(i, NUMBER_OF_CALLS) {
	if (i < NUMBER_OF_CALLS) {
		rl.request('123456', function(err, res) {
			if (err)
				console.log("REQUEST NOT ALLOWED for user: " +
					err.uid + " | LIMIT(s) REACHED: " + err.reachedLimits);
			else
				console.log("REQUEST ALLOWED for user: " + res.uid);
			// Send the next request
			requestDispatcher(i+1, NUMBER_OF_CALLS);
		});
	}
};

// Send requests for two users one after another
var simultaneousRequestDispatcher = function(i, NUMBER_OF_CALLS) {

	if (i < NUMBER_OF_CALLS) {
		// If i is even, send request as user1, send it as user2 otherwise
		if (i % 2 == 0) {
			rl.request('user1', function(err, res) {
				if (err)
					console.log("REQUEST #" + (i+1) + " IS NOT ALLOWED for user: " +
						err.uid + " | LIMIT(s) REACHED: " + err.reachedLimits);
				else
					console.log("REQUEST #" + (i+1) + " IS ALLOWED for user: " + res.uid);
			// Send the next request
			simultaneousRequestDispatcher(i+1, NUMBER_OF_CALLS);
			});
		} else {
			rl.request('user2', function(err, res) {
				if (err)
					console.log("REQUEST #" + (i+1) + " IS NOT ALLOWED for user: " +
						err.uid + " | LIMIT(s) REACHED: " + err.reachedLimits);
				else
					console.log("REQUEST #"+ (i+1) + " IS ALLOWED for user: " + res.uid);
			// Send the next request
			simultaneousRequestDispatcher(i+1, NUMBER_OF_CALLS);
			});
		}
	}

};

// Start sending the requests
// requestDispatcher(0, 201);

simultaneousRequestDispatcher(0, 201);
<|endoftext|>


<commit_before>/*
 *  Copyright 2013 David Farrell
 *
 *  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 fs = require('fs')
var util = require('util')
var parser = require('./parser')

var Fn = function(ins, outs, code)
{
    this.type = 'function'
    this.ins = ins
    this.outs = outs
    this.code = code
    this.toString = function() { return '[shockklang Fn]' }
}

var BindingFn = function(fn)
{
    this.type = 'function'
    this.fn = fn
    this.is_binding = true
    this.toString = function() { return '[shockklang Fn]' }
}

var state =
{
    scope: [{}],
}

state.top = function()
{
    return this.scope[this.scope.length - 1]
}

state.get = function(name)
{
    for(var i=this.scope.length-1; i>0; --i)
    {
        if(this.scope[i][name] !== undefined) return this.scope[i][name]
    }
    return this.scope[0][name]
}

state.bind_function = function(fn, name)
{
    state.scope[0][name] = new BindingFn(fn)
}

state.binding_call = function(fn, paramlist)
{
    if(paramlist === undefined) paramlist = []

    if(paramlist.length < fn.length - 1)
        throw new Error('not enough params')

    if(paramlist.length > fn.length - 1)
        console.log('\x1B[1m\x1B[33m-> warning <-\x1B[0m too many params, truncating')

    // evaluate each param in the param list
    var params = paramlist.map(function(v, k, a)
    {
        return state.evaluate(v)
    }).slice(0, fn.length - 1)

    var result = fn.apply(state.top(), [state].concat(params))
    return result !== undefined ? result : '[shockklang undefined]'
}

state.call = function(fn, paramlist)
{
    if(fn.is_binding) return state.binding_call(fn.fn, paramlist)

    if(paramlist === undefined) paramlist = []

    if(paramlist.length < fn.ins.length)
        throw new Error('not enough params')

    if(paramlist.length > fn.ins.length)
        console.log('\x1B[1m\x1B[33m-> warning <-\x1B[0m too many params, truncating')

    // evaluate each param in the param list
    var params = paramlist.map(function(v, k, a)
    {
        return state.evaluate(v)
    }).slice(0, fn.ins.length)

    var scope = {}

    // put inputs into function scope
    var i = 0
    for(var k in fn.ins)
    {
        scope[fn.ins[k].data] = params[i++]
    }

    // set initial values of outputs
    for(var k in fn.outs)
    {
        fn.last_outputs === undefined
        ? scope[fn.outs[k].identifier.data] = state.evaluate(fn.outs[k].initial)
        : scope[fn.outs[k].identifier.data] = fn.last_outputs[fn.outs[k].identifier.data]
    }

    state.scope.push(scope)

    // evaluate each statement in function code
    for(var i=0; i<fn.code.length; ++i)
    {
        state.evaluate(fn.code[i])

        if(state.function_ahead === true)
        {
            state.function_ahead = false
            break
        }
    }

    // get outputs from function scope
    fn.last_outputs = {}
    var outputs = fn.outs.map(function(v, k, a)
    {
        fn.last_outputs[v.identifier.data] = state.get(v.identifier.data)
        return state.get(v.identifier.data)
    })

    state.scope.pop()

    switch(outputs.length)
    {
        case 0: return undefined
        case 1: return outputs[0]
        default: return outputs
    }
}

state.evaluate = function(obj)
{
    switch(typeof obj)
    {
        case 'object': break
        case 'undefined': return '[shockklang undefined]'
        default: return obj.toString()
    }

    switch(obj.type)
    {
        case '=':
            return (state.top()[obj.left.data] = state.evaluate(obj.right))
        case '+':
            return state.evaluate(obj.left) + state.evaluate(obj.right)
        case '-':
            return state.evaluate(obj.left) - state.evaluate(obj.right)
        case '*':
            return state.evaluate(obj.left) * state.evaluate(obj.right)
        case '&':
            return state.evaluate(obj.left) & state.evaluate(obj.right)
        case '|':
            return state.evaluate(obj.left) | state.evaluate(obj.right)
        case '<<':
            return state.evaluate(obj.left) << state.evaluate(obj.right)
        case '>>':
            return state.evaluate(obj.left) >> state.evaluate(obj.right)
        case '==':
            return state.evaluate(obj.left) == state.evaluate(obj.right)
        case 'number':
        case 'string':
            return obj.data
        case 'identifier':
            return state.get(obj.data)
        case 'conditional':
            for(var i=0; i<obj.data.length; ++i)
            {
                var condition = obj.data[i].condition === undefined
                              ? true
                              : state.evaluate(obj.data[i].condition)

                if(condition !== undefined && condition !== null && condition !== 0 && condition !== false)
                {
                    var result
                    obj.data[i].code.forEach(function(v, k, a)
                    {
                        result = state.evaluate(v)
                    })
                    return result
                }
            }
            return undefined
        case 'function':
            return new Fn(obj.ins, obj.outs, obj.code)
        case 'call':
        case 'anoncall':
            if(obj.type === 'call') var fn = state.get(obj.identifier.data)
            else var fn = obj.fn

            if(fn === undefined)
                throw new Error('identifier `' + obj.identifier.data + '` is undefined')

            if(fn.type !== 'function')
                throw new Error('identifier `' + obj.identifier.data + '` is not a function')

            var result
            obj.paramlists.forEach(function(v, k, a)
            {
                result = state.call(fn, v)
            })
            fn.last_outputs = undefined
            delete fn.last_outputs

            return result !== undefined ? result : '[shockklang undefined]'
        case 'function_ahead':
            state.function_ahead = true
            return
        case 'infix':
            throw new Error('infix not implemented')
        default:
            if(obj.type !== undefined) console.log('type unhandled: ' + obj.type)
            else                       console.log('type missing: ' + util.inspect(obj[0]))
            break
        // TODO: implement scope for blocks too
    }
}

// load and bind all function bindings
var bindings = require('./bindings')
for(var k in bindings) state.bind_function(bindings[k], k)

var filename = process.argv[2]
fs.readFile(filename, function(err, data)
{
    if(err) throw err
    try
    {
        parser.parse(data.toString()).forEach(function(v, k, a)
        {
            state.evaluate(v)
        })
    }
    catch(e)
    {
        console.log(e)
        return
    }
})
<commit_msg>Fixed scope brokenness for assignments.<commit_after>/*
 *  Copyright 2013 David Farrell
 *
 *  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 fs = require('fs')
var util = require('util')
var parser = require('./parser')

var Fn = function(ins, outs, code)
{
    this.type = 'function'
    this.ins = ins
    this.outs = outs
    this.code = code
    this.toString = function() { return '[shockklang Fn]' }
}

var BindingFn = function(fn)
{
    this.type = 'function'
    this.fn = fn
    this.is_binding = true
    this.toString = function() { return '[shockklang Fn]' }
}

var state =
{
    scope: [{}],
}

state.top = function()
{
    return this.scope[this.scope.length - 1]
}

state.set = function(name, value)
{
    for(var i=this.scope.length-1; i>=0; --i)
    {
        if(this.scope[i][name] !== undefined) return (this.scope[i][name] = value)
    }
    return (this.top()[name] = value)
}

state.get = function(name)
{
    for(var i=this.scope.length-1; i>0; --i)
    {
        if(this.scope[i][name] !== undefined) return this.scope[i][name]
    }
    return this.scope[0][name]
}

state.bind_function = function(fn, name)
{
    state.scope[0][name] = new BindingFn(fn)
}

state.binding_call = function(fn, paramlist)
{
    if(paramlist === undefined) paramlist = []

    if(paramlist.length < fn.length - 1)
        throw new Error('not enough params')

    if(paramlist.length > fn.length - 1)
        console.log('\x1B[1m\x1B[33m-> warning <-\x1B[0m too many params, truncating')

    // evaluate each param in the param list
    var params = paramlist.map(function(v, k, a)
    {
        return state.evaluate(v)
    }).slice(0, fn.length - 1)

    var result = fn.apply(state.top(), [state].concat(params))
    return result !== undefined ? result : '[shockklang undefined]'
}

state.call = function(fn, paramlist)
{
    if(fn.is_binding) return state.binding_call(fn.fn, paramlist)

    if(paramlist === undefined) paramlist = []

    if(paramlist.length < fn.ins.length)
        throw new Error('not enough params')

    if(paramlist.length > fn.ins.length)
        console.log('\x1B[1m\x1B[33m-> warning <-\x1B[0m too many params, truncating')

    // evaluate each param in the param list
    var params = paramlist.map(function(v, k, a)
    {
        return state.evaluate(v)
    }).slice(0, fn.ins.length)

    var scope = {}

    // put inputs into function scope
    var i = 0
    for(var k in fn.ins)
    {
        scope[fn.ins[k].data] = params[i++]
    }

    // set initial values of outputs
    for(var k in fn.outs)
    {
        fn.last_outputs === undefined
        ? scope[fn.outs[k].identifier.data] = state.evaluate(fn.outs[k].initial)
        : scope[fn.outs[k].identifier.data] = fn.last_outputs[fn.outs[k].identifier.data]
    }

    state.scope.push(scope)

    // evaluate each statement in function code
    for(var i=0; i<fn.code.length; ++i)
    {
        state.evaluate(fn.code[i])

        if(state.function_ahead === true)
        {
            state.function_ahead = false
            break
        }
    }

    // get outputs from function scope
    fn.last_outputs = {}
    var outputs = fn.outs.map(function(v, k, a)
    {
        fn.last_outputs[v.identifier.data] = state.get(v.identifier.data)
        return state.get(v.identifier.data)
    })

    state.scope.pop()

    switch(outputs.length)
    {
        case 0: return undefined
        case 1: return outputs[0]
        default: return outputs
    }
}

state.evaluate = function(obj)
{
    switch(typeof obj)
    {
        case 'object': break
        case 'undefined': return '[shockklang undefined]'
        default: return obj.toString()
    }

    switch(obj.type)
    {
        case '=':
            return state.set(obj.left.data, state.evaluate(obj.right))
        case '+':
            return state.evaluate(obj.left) + state.evaluate(obj.right)
        case '-':
            return state.evaluate(obj.left) - state.evaluate(obj.right)
        case '*':
            return state.evaluate(obj.left) * state.evaluate(obj.right)
        case '&':
            return state.evaluate(obj.left) & state.evaluate(obj.right)
        case '|':
            return state.evaluate(obj.left) | state.evaluate(obj.right)
        case '<<':
            return state.evaluate(obj.left) << state.evaluate(obj.right)
        case '>>':
            return state.evaluate(obj.left) >> state.evaluate(obj.right)
        case '==':
            return state.evaluate(obj.left) == state.evaluate(obj.right)
        case 'number':
        case 'string':
            return obj.data
        case 'identifier':
            return state.get(obj.data)
        case 'conditional':
            for(var i=0; i<obj.data.length; ++i)
            {
                var condition = obj.data[i].condition === undefined
                              ? true
                              : state.evaluate(obj.data[i].condition)

                if(condition !== undefined && condition !== null && condition !== 0 && condition !== false)
                {
                    var result
                    obj.data[i].code.forEach(function(v, k, a)
                    {
                        result = state.evaluate(v)
                    })
                    return result
                }
            }
            return undefined
        case 'function':
            return new Fn(obj.ins, obj.outs, obj.code)
        case 'call':
        case 'anoncall':
            if(obj.type === 'call') var fn = state.get(obj.identifier.data)
            else var fn = obj.fn

            if(fn === undefined)
                throw new Error('identifier `' + obj.identifier.data + '` is undefined')

            if(fn.type !== 'function')
                throw new Error('identifier `' + obj.identifier.data + '` is not a function')

            var result
            obj.paramlists.forEach(function(v, k, a)
            {
                result = state.call(fn, v)
            })
            fn.last_outputs = undefined
            delete fn.last_outputs

            return result !== undefined ? result : '[shockklang undefined]'
        case 'function_ahead':
            state.function_ahead = true
            return
        case 'infix':
            throw new Error('infix not implemented')
        default:
            if(obj.type !== undefined) console.log('type unhandled: ' + obj.type)
            else                       console.log('type missing: ' + util.inspect(obj[0]))
            break
        // TODO: implement scope for blocks too
    }
}

// load and bind all function bindings
var bindings = require('./bindings')
for(var k in bindings) state.bind_function(bindings[k], k)

var filename = process.argv[2]
fs.readFile(filename, function(err, data)
{
    if(err) throw err
    try
    {
        parser.parse(data.toString()).forEach(function(v, k, a)
        {
            state.evaluate(v)
        })
    }
    catch(e)
    {
        console.log(e)
        return
    }
})
<|endoftext|>


<commit_before>var _ = require('lodash'),
AWS = require('aws-sdk'),
cfValidate = require('./lib/gulp-cf-validate'),
cutil = require('./lib/util'),
del = require('del'),
gulpif = require('gulp-if'),
gutil = require('gulp-util'),
handlebars = require('gulp-compile-handlebars'),
jsonlint = require('gulp-jsonlint'),
merge = require('merge-stream'),
path = require('path'),
rename = require('gulp-rename'),
through = require('through2');

var DEFAULT_TASK_PREFIX = exports.DEFAULT_TASK_PREFIX = 'condensation';
var PARTICLES_DIR = exports.PARTICLES_DIR = 'particles';
var DEFAULT_ROOT = exports.DEFAULT_ROOT = './';

var Condensation = function(gulp,options) {
  this.gulp = gulp;
  this.options = options = _.merge({
    dist: 'dist',
    root: DEFAULT_ROOT,
    dependencySrc: [],
    taskPrefix: DEFAULT_TASK_PREFIX
  },options);
  options.particlesDir = path.join(options.root,PARTICLES_DIR);

  if (!options.projectName) {
    try { options.projectName = require(process.cwd()+'/bower.json').name; } catch(e) {}
  }

  this.genTaskName = cutil.genTaskNameFunc({prefix:options.taskPrefix});
  this.condense();
};

Condensation.prototype.condense = function() {
  var self = this;
  var options = this.options;

  var gulp = this.gulp || require('gulp');

  var partials = {};
  var buildTasks = [];
  var deployTasks = [];

  var s3config = options.s3 || [];

  _.each(s3config, function(s3opts,i) {
    var templateData = {};
    var s3 = new AWS.S3({region: s3opts.aws.region});

    templateData.s3 = s3opts.aws;
    templateData.s3.awsPath = s3.endpoint.href+s3opts.aws.bucket;

    gulp.task(self.genTaskName('assets','compile',i),[self.genTaskName('partials','load')],function() {
      var mergeStreams = self._buildDepParticleStreams('assets',true);

      var stream = merge.apply(null,mergeStreams).add(gulp.src(["assets/**"],{cwd:options.particlesDir}))
      .pipe(gulpif(/\.hbs$/,handlebars(templateData,{partials:partials})))
      .pipe(gulpif(/\.hbs$/,rename({extname:""})))
      .pipe(rename({dirname:path.join.apply(null,_.compact([options.projectName,"assets"]))}));

      return stream.pipe(gulp.dest(path.join(options.dist,i.toString())));
    });

    // Compile all templates with handlebars
    gulp.task(self.genTaskName('templates','compile',i),[self.genTaskName('partials','load')],function() {
      var mergeStreams = self._buildDepParticleStreams('cftemplates',true);

      // source project
      var spStream = gulp.src(["cftemplates/**"],{cwd:options.particlesDir})
      .pipe(rename({dirname: path.join(options.projectName,'cftemplates')}));
      mergeStreams.push(spStream);

      var stream = merge.apply(null,mergeStreams)
      .pipe(gulpif(/\.hbs$/,handlebars(templateData,{partials:partials})))
      .pipe(gulpif(/\.hbs$/,rename({extname:""})))
      .pipe(jsonlint())
      .pipe(jsonlint.reporter());

      if (s3opts.validate) {
        stream = stream.pipe(cfValidate({region: s3opts.aws.region}));
      }

      return stream.pipe(gulp.dest(path.join(options.dist,i.toString())));
    });

    // set build tasks
    gulp.task(self.genTaskName('build',i), [self.genTaskName('assets','compile',i),self.genTaskName('templates','compile',i)]);
    buildTasks.push(self.genTaskName('build',i));

    // Ensure the bucket(s) defined in the config exist
    gulp.task(self.genTaskName('s3','bucket','ensure',i),function(cb) {
      s3.headBucket({
        Bucket: s3opts.aws.bucket
      },function(err,data){
        if (err && err.code === 'NotFound' && s3opts.create) {
          s3.createBucket({
            Bucket: s3opts.aws.bucket
          },cb);
        }
        else {
          cb(null,data);
          //TODO Removed for cross account access.  Need to revisit s3 bucket permissions and correct fallback
          // cb(err,data);
        }
      });
    });

    // Write objects to s3
    gulp.task(
      self.genTaskName('s3','objects','write',i),
      [
        self.genTaskName('s3','bucket','ensure',i),
        self.genTaskName('build',i)
      ],
      function() {
      var streams = [];
      _.each([path.join(options.dist,i.toString()),path.join(options.dist,'shared')],function(srcDir) {
        var stream = gulp.src("**",{cwd:srcDir}).on("data",function(file) {
          if (file.stat.isFile()) {
            var newFilename = file.relative;

            s3.putObject({
              Bucket: s3opts.aws.bucket,
              ACL: "bucket-owner-full-control",
              //ACL: "private",
              Key: newFilename,
              Body: file.contents
            },function(err,data) {
              if (err) {
                // TODO throw error
                console.warn(err);
              }
            });
          }
        });
        streams.push(stream);
      });
      return merge.apply(null,streams);
    });

    gulp.task(self.genTaskName('deploy',i),[self.genTaskName('s3','objects','write',i)]);
    deployTasks.push(self.genTaskName('deploy',i));

  });

  // Remove all files from 'dist'
  gulp.task(self.genTaskName('clean'), function (cb) {
    del([
      options.dist
    ], cb);
  });

  // Register all partials for use with templates
  gulp.task(self.genTaskName('partials','load'),function(cb) {
    var mergeStreams = self._buildDepParticleStreams('partials',true);

    return merge.apply(null,mergeStreams).add(gulp.src("partials/**",{cwd:self.options.particlesDir}))
    .pipe(through.obj(function(file, enc, cb) {
      //console.log(file);
      if (file.contents) {
        partials[file.relative.replace(/\.hbs$/,"")] = file.contents.toString();
      }
      cb(null,file);
    }));
  });

  gulp.task(self.genTaskName('s3','list'), function(cb) {
    _.each(s3config, function(s3opts,i) {
      gutil.log(i + ": " + s3opts.aws.bucket);
    });
    cb();
  });

  // Tasks to launch other tasks
  gulp.task(self.genTaskName('build'),buildTasks);
  gulp.task(self.genTaskName('deploy'), deployTasks);
  gulp.task(self.genTaskName('default'),[self.genTaskName('build')]);

};

Condensation.prototype._buildDepParticleStreams = function(particle,incParticleInPath) {
  var gulp = this.gulp;

  var streams = [];
  _.each(this.options.dependencySrc,function(dir) {
    var depSrc = gulp.src([path.join("*",'particles',particle,"**")],{cwd:dir})
    .pipe(rename(function(path) {
      path.dirname = path.dirname.replace(new RegExp("/"+PARTICLES_DIR+"/?"),'/');
      if (incParticleInPath === false) {
        path.basename = path.basename.replace(new RegExp(particle),'');
        path.dirname = path.dirname.replace(new RegExp("/"+particle+"/?"),'/');
      }
    }));
    streams.push(depSrc);
  });
  return streams;
};

module.exports.buildTasks = function(gulp,options) {
  return new Condensation(gulp,options);
};
<commit_msg>partials should no include particle name in path<commit_after>var _ = require('lodash'),
AWS = require('aws-sdk'),
cfValidate = require('./lib/gulp-cf-validate'),
cutil = require('./lib/util'),
del = require('del'),
gulpif = require('gulp-if'),
gutil = require('gulp-util'),
handlebars = require('gulp-compile-handlebars'),
jsonlint = require('gulp-jsonlint'),
merge = require('merge-stream'),
path = require('path'),
rename = require('gulp-rename'),
through = require('through2');

var DEFAULT_TASK_PREFIX = exports.DEFAULT_TASK_PREFIX = 'condensation';
var PARTICLES_DIR = exports.PARTICLES_DIR = 'particles';
var DEFAULT_ROOT = exports.DEFAULT_ROOT = './';

var Condensation = function(gulp,options) {
  this.gulp = gulp;
  this.options = options = _.merge({
    dist: 'dist',
    root: DEFAULT_ROOT,
    dependencySrc: [],
    taskPrefix: DEFAULT_TASK_PREFIX
  },options);
  options.particlesDir = path.join(options.root,PARTICLES_DIR);

  if (!options.projectName) {
    try { options.projectName = require(process.cwd()+'/bower.json').name; } catch(e) {}
  }

  this.genTaskName = cutil.genTaskNameFunc({prefix:options.taskPrefix});
  this.condense();
};

Condensation.prototype.condense = function() {
  var self = this;
  var options = this.options;

  var gulp = this.gulp || require('gulp');

  var partials = {};
  var helpers = {};
  var buildTasks = [];
  var deployTasks = [];

  var s3config = options.s3 || [];

  _.each(s3config, function(s3opts,i) {
    var templateData = {};
    var s3 = new AWS.S3({region: s3opts.aws.region});

    templateData.s3 = s3opts.aws;
    templateData.s3.awsPath = s3.endpoint.href+s3opts.aws.bucket;

    gulp.task(self.genTaskName('assets','compile',i),[self.genTaskName('partials','load')],function() {
      var mergeStreams = self._buildDepParticleStreams('assets',true);

      var stream = merge.apply(null,mergeStreams).add(gulp.src(["assets/**"],{cwd:options.particlesDir}))
      .pipe(gulpif(/\.hbs$/,handlebars(templateData,{partials:partials})))
      .pipe(gulpif(/\.hbs$/,rename({extname:""})))
      .pipe(rename({dirname:path.join.apply(null,_.compact([options.projectName,"assets"]))}));

      return stream.pipe(gulp.dest(path.join(options.dist,i.toString())));
    });

    // Compile all templates with handlebars
    gulp.task(self.genTaskName('templates','compile',i),[self.genTaskName('partials','load')],function() {
      var mergeStreams = self._buildDepParticleStreams('cftemplates',true);

      // source project
      var spStream = gulp.src(["cftemplates/**"],{cwd:options.particlesDir})
      .pipe(rename({dirname: path.join(options.projectName,'cftemplates')}));
      mergeStreams.push(spStream);

      var stream = merge.apply(null,mergeStreams)
      .pipe(gulpif(/\.hbs$/,handlebars(templateData,{partials:partials})))
      .pipe(gulpif(/\.hbs$/,rename({extname:""})))
      .pipe(jsonlint())
      .pipe(jsonlint.reporter());

      if (s3opts.validate) {
        stream = stream.pipe(cfValidate({region: s3opts.aws.region}));
      }

      return stream.pipe(gulp.dest(path.join(options.dist,i.toString())));
    });

    // set build tasks
    gulp.task(self.genTaskName('build',i), [self.genTaskName('assets','compile',i),self.genTaskName('templates','compile',i)]);
    buildTasks.push(self.genTaskName('build',i));

    // Ensure the bucket(s) defined in the config exist
    gulp.task(self.genTaskName('s3','bucket','ensure',i),function(cb) {
      s3.headBucket({
        Bucket: s3opts.aws.bucket
      },function(err,data){
        if (err && err.code === 'NotFound' && s3opts.create) {
          s3.createBucket({
            Bucket: s3opts.aws.bucket
          },cb);
        }
        else {
          cb(null,data);
          //TODO Removed for cross account access.  Need to revisit s3 bucket permissions and correct fallback
          // cb(err,data);
        }
      });
    });

    // Write objects to s3
    gulp.task(
      self.genTaskName('s3','objects','write',i),
      [
        self.genTaskName('s3','bucket','ensure',i),
        self.genTaskName('build',i)
      ],
      function() {
      var streams = [];
      _.each([path.join(options.dist,i.toString()),path.join(options.dist,'shared')],function(srcDir) {
        var stream = gulp.src("**",{cwd:srcDir}).on("data",function(file) {
          if (file.stat.isFile()) {
            var newFilename = file.relative;

            s3.putObject({
              Bucket: s3opts.aws.bucket,
              ACL: "bucket-owner-full-control",
              //ACL: "private",
              Key: newFilename,
              Body: file.contents
            },function(err,data) {
              if (err) {
                // TODO throw error
                console.warn(err);
              }
            });
          }
        });
        streams.push(stream);
      });
      return merge.apply(null,streams);
    });

    gulp.task(self.genTaskName('deploy',i),[self.genTaskName('s3','objects','write',i)]);
    deployTasks.push(self.genTaskName('deploy',i));

  });

  // Remove all files from 'dist'
  gulp.task(self.genTaskName('clean'), function (cb) {
    del([
      options.dist
    ], cb);
  });

  // Register all partials for use with templates
  gulp.task(self.genTaskName('partials','load'),function(cb) {
    var mergeStreams = self._buildDepParticleStreams('partials',false);

    return merge.apply(null,mergeStreams).add(gulp.src("partials/**",{cwd:self.options.particlesDir}))
    .pipe(through.obj(function(file, enc, cb) {
      if (file.contents) {
        partials[file.relative.replace(/\.hbs$/,"")] = file.contents.toString();
      }
      cb(null,file);
    }));
  });

  gulp.task(self.genTaskName('s3','list'), function(cb) {
    _.each(s3config, function(s3opts,i) {
      gutil.log(i + ": " + s3opts.aws.bucket);
    });
    cb();
  });

  // Tasks to launch other tasks
  gulp.task(self.genTaskName('build'),buildTasks);
  gulp.task(self.genTaskName('deploy'), deployTasks);
  gulp.task(self.genTaskName('default'),[self.genTaskName('build')]);

};

Condensation.prototype._buildDepParticleStreams = function(particle,incParticleInPath) {
  var gulp = this.gulp;

  var streams = [];
  _.each(this.options.dependencySrc,function(dir) {
    var depSrc = gulp.src([path.join("*",'particles',particle,"**")],{cwd:dir})
    .pipe(rename(function(path) {
      path.dirname = path.dirname.replace(new RegExp("/"+PARTICLES_DIR+"/?"),'/');
      if (incParticleInPath === false) {
        path.basename = path.basename.replace(new RegExp(particle),'');
        path.dirname = path.dirname.replace(new RegExp("/"+particle+"/?"),'/');
      }
    }));
    streams.push(depSrc);
  });
  return streams;
};

module.exports.buildTasks = function(gulp,options) {
  return new Condensation(gulp,options);
};
<|endoftext|>


<commit_before>'use strict';

const _ = require('lodash');
const got = require('got');
const debug = require('debug')('slack-helper');

const SLACK_API = 'https://slack.com/api/';

/**
 * slack-helper class
 *
 * @param String Slack API Token
 */
function slackHelper(token) {
  if (!(this instanceof slackHelper)) {
    return new slackHelper(token);
  }

  if (!_.isString(token)) {
    throw new Error('Need an valid slack api token');
  }

  this.token = token;
}

slackHelper.prototype = {
  send: function(channel, message, opts) {
    let self = this;
    let reqUrl = `${SLACK_API}/chat.postMessage`;

    return new Promise(function(resolve, reject) {
      got.post(reqUrl, {
        json: true,
        body: {
          token : self.token,
          channel: channel,
          text: message
        }
      }).then((resp) => {
        let result = resp.body;

        return (result.ok !== true)
          ? reject(new Error(result.error))
          : resolve(result);
      }).catch((error) => {
        reject(error);
      });
    });
  }
};

module.exports = slackHelper;
module.exports.default = module.exports;
<commit_msg>remove debug temporary<commit_after>'use strict';

const _ = require('lodash');
const got = require('got');

const SLACK_API = 'https://slack.com/api/';

/**
 * slack-helper class
 *
 * @param String Slack API Token
 */
function slackHelper(token) {
  if (!(this instanceof slackHelper)) {
    return new slackHelper(token);
  }

  if (!_.isString(token)) {
    throw new Error('Need an valid slack api token');
  }

  this.token = token;
}

slackHelper.prototype = {
  send: function(channel, message, opts) {
    let self = this;
    let reqUrl = `${SLACK_API}/chat.postMessage`;

    return new Promise(function(resolve, reject) {
      got.post(reqUrl, {
        json: true,
        body: {
          token : self.token,
          channel: channel,
          text: message
        }
      }).then((resp) => {
        let result = resp.body;

        return (result.ok !== true)
          ? reject(new Error(result.error))
          : resolve(result);
      }).catch((error) => {
        reject(error);
      });
    });
  }
};

module.exports = slackHelper;
module.exports.default = module.exports;
<|endoftext|>


<commit_before>const {findWrapping, liftTarget, canSplit, ReplaceAroundStep} = require("../transform")
const {Block, Attribute, Slice, Fragment, NodeRange} = require("../model")

// ::- An ordered list node type. Has a single attribute, `order`,
// which determines the number at which the list starts counting, and
// defaults to 1.
class OrderedList extends Block {
  get attrs() { return {order: new Attribute({default: 1})} }
  get matchDOMTag() {
    return {"ol": dom => ({
      order: dom.hasAttribute("start") ? +dom.getAttribute("start") : 1
    })}
  }
  toDOM(node) {
    return ["ol", {start: node.attrs.order == 1 ? null : node.attrs.order}, 0]
  }
}
exports.OrderedList = OrderedList

// ::- A bullet list node type.
class BulletList extends Block {
  get matchDOMTag() { return {"ul": null} }
  toDOM() { return ["ul", 0] }
}
exports.BulletList = BulletList

// ::- A list item node type.
class ListItem extends Block {
  get matchDOMTag() { return {"li": null} }
  toDOM() { return ["li", 0] }
}
exports.ListItem = ListItem

// :: (OrderedMap, string, ?string) → OrderedMap
// Convenience function for adding list-related node types to a map
// describing the nodes in a schema. Adds `OrderedList` as
// `"ordered_list"`, `BulletList` as `"bullet_list"`, and `ListItem`
// as `"list_item"`. `itemContent` determines the content expression
// for the list items. If you want the commands defined in this module
// to apply to your list structure, it should have a shape like
// `"paragraph block*"`, a plain textblock type followed by zero or
// more arbitrary nodes. `listGroup` can be given to assign a group
// name to the list node types, for example `"block"`.
function addListNodes(nodes, itemContent, listGroup) {
  return nodes.append({
    ordered_list: {type: OrderedList, content: "list_item+", group: listGroup},
    bullet_list: {type: BulletList, content: "list_item+", group: listGroup},
    list_item: {type: ListItem, content: itemContent}
  })
}
exports.addListNodes = addListNodes

// !! This module exports a number of list-related commands, which
// assume lists to be nestable, but with the restriction that the
// first child of a list item is not a list.

// :: (NodeType, ?Object) → (state: EditorState, onAction: ?(action: Object)) → bool
// Returns a command function that wraps the selection in a list with
// the given type an attributes. If `apply` is `false`, only return a
// value to indicate whether this is possible, but don't actually
// perform the change.
function wrapInList(nodeType, attrs) {
  return function(state, onAction) {
    let {$from, $to} = state.selection
    let range = $from.blockRange($to), doJoin = false, outerRange = range
    // This is at the top of an existing list item
    if (range.depth >= 2 && $from.node(range.depth - 1).type.compatibleContent(nodeType) && range.startIndex == 0) {
      // Don't do anything if this is the top of the list
      if ($from.index(range.depth - 1) == 0) return false
      let $insert = state.doc.resolve(range.start - 2)
      outerRange = new NodeRange($insert, $insert, range.depth)
      if (range.endIndex < range.parent.childCount)
        range = new NodeRange($from, state.doc.resolve($to.end(range.depth)), range.depth)
      doJoin = true
    }
    let wrap = findWrapping(outerRange, nodeType, attrs, range)
    if (!wrap) return false
    if (onAction) onAction(doWrapInList(state.tr, range, wrap, doJoin, nodeType).scrollAction())
    return true
  }
}
exports.wrapInList = wrapInList

function doWrapInList(tr, range, wrappers, joinBefore, nodeType) {
  let content = Fragment.empty
  for (let i = wrappers.length - 1; i >= 0; i--)
    content = Fragment.from(wrappers[i].type.create(wrappers[i].attrs, content))

  tr.step(new ReplaceAroundStep(range.start - (joinBefore ? 2 : 0), range.end, range.start, range.end,
                                new Slice(content, 0, 0), wrappers.length, true))

  let found = 0
  for (let i = 0; i < wrappers.length; i++) if (wrappers[i].type == nodeType) found = i + 1
  let splitDepth = wrappers.length - found

  let splitPos = range.start + wrappers.length - (joinBefore ? 2 : 0), parent = range.parent
  for (let i = range.startIndex, e = range.endIndex, first = true; i < e; i++, first = false) {
    if (!first && canSplit(tr.doc, splitPos, splitDepth)) tr.split(splitPos, splitDepth)
    splitPos += parent.child(i).nodeSize + (first ? 0 : 2 * splitDepth)
  }
  return tr
}

// :: (NodeType) → (state: EditorState) → bool
// Build a command that splits a non-empty textblock at the top level
// of a list item by also splitting that list item.
function splitListItem(nodeType) {
  return function(state, onAction) {
    let {$from, $to, node} = state.selection
    if ((node && node.isBlock) || !$from.parent.content.size ||
        $from.depth < 2 || !$from.sameParent($to)) return false
    let grandParent = $from.node(-1)
    if (grandParent.type != nodeType) return false
    let nextType = $to.pos == $from.end() ? grandParent.defaultContentType($from.indexAfter(-1)) : null
    let tr = state.tr.delete($from.pos, $to.pos)
    if (!canSplit(tr.doc, $from.pos, 2, nextType)) return false
    if (onAction) onAction(tr.split($from.pos, 2, nextType).scrollAction())
    return true
  }
}
exports.splitListItem = splitListItem

// :: (NodeType) → (state: EditorState, onAction: ?(action: Object)) → bool
// Create a command to lift the list item around the selection up into
// a wrapping list.
function liftListItem(nodeType) {
  return function(state, onAction) {
    let {$from, $to} = state.selection
    let range = $from.blockRange($to, node => node.childCount && node.firstChild.type == nodeType)
    if (!range || range.depth < 2 || $from.node(range.depth - 1).type != nodeType) return false
    if (onAction) {
      let tr = state.tr, end = range.end, endOfList = $to.end(range.depth)
      if (end < endOfList) {
        // There are siblings after the lifted items, which must become
        // children of the last item
        tr.step(new ReplaceAroundStep(end - 1, endOfList, end, endOfList,
                                      new Slice(Fragment.from(nodeType.create(null, range.parent.copy())), 1, 0), 1, true))
        range = new NodeRange(tr.doc.resolveNoCache($from.pos), tr.doc.resolveNoCache(endOfList), range.depth)
      }
      onAction(tr.lift(range, liftTarget(range)).scrollAction())
    }
    return true
  }
}
exports.liftListItem = liftListItem

// :: (NodeType) → (state: EditorState, onAction: ?(action: Object)) → bool
// Create a command to sink the list item around the selection down
// into an inner list.
function sinkListItem(nodeType) {
  return function(state, onAction) {
    let {$from, $to} = state.selection
    let range = $from.blockRange($to, node => node.childCount && node.firstChild.type == nodeType)
    if (!range) return false
    let startIndex = range.startIndex
    if (startIndex == 0) return false
    let parent = range.parent, nodeBefore = parent.child(startIndex - 1)
    if (nodeBefore.type != nodeType) return false

    if (onAction) {
      let nestedBefore = nodeBefore.lastChild && nodeBefore.lastChild.type == parent.type
      let inner = Fragment.from(nestedBefore ? nodeType.create() : null)
      let slice = new Slice(Fragment.from(nodeType.create(null, Fragment.from(parent.copy(inner)))),
                            nestedBefore ? 3 : 1, 0)
      let before = range.start, after = range.end
      onAction(state.tr.step(new ReplaceAroundStep(before - (nestedBefore ? 3 : 1), after,
                                                   before, after, slice, 1, true))
               .scrollAction())
    }
    return true
  }
}
exports.sinkListItem = sinkListItem
<commit_msg>Use new anchor style in internal doc links<commit_after>const {findWrapping, liftTarget, canSplit, ReplaceAroundStep} = require("../transform")
const {Block, Attribute, Slice, Fragment, NodeRange} = require("../model")

// ::- An ordered list node type. Has a single attribute, `order`,
// which determines the number at which the list starts counting, and
// defaults to 1.
class OrderedList extends Block {
  get attrs() { return {order: new Attribute({default: 1})} }
  get matchDOMTag() {
    return {"ol": dom => ({
      order: dom.hasAttribute("start") ? +dom.getAttribute("start") : 1
    })}
  }
  toDOM(node) {
    return ["ol", {start: node.attrs.order == 1 ? null : node.attrs.order}, 0]
  }
}
exports.OrderedList = OrderedList

// ::- A bullet list node type.
class BulletList extends Block {
  get matchDOMTag() { return {"ul": null} }
  toDOM() { return ["ul", 0] }
}
exports.BulletList = BulletList

// ::- A list item node type.
class ListItem extends Block {
  get matchDOMTag() { return {"li": null} }
  toDOM() { return ["li", 0] }
}
exports.ListItem = ListItem

// :: (OrderedMap, string, ?string) → OrderedMap
// Convenience function for adding list-related node types to a map
// describing the nodes in a schema. Adds `OrderedList` as
// `"ordered_list"`, `BulletList` as `"bullet_list"`, and `ListItem`
// as `"list_item"`. `itemContent` determines the content expression
// for the list items. If you want the commands defined in this module
// to apply to your list structure, it should have a shape like
// `"paragraph block*"`, a plain textblock type followed by zero or
// more arbitrary nodes. `listGroup` can be given to assign a group
// name to the list node types, for example `"block"`.
function addListNodes(nodes, itemContent, listGroup) {
  return nodes.append({
    ordered_list: {type: OrderedList, content: "list_item+", group: listGroup},
    bullet_list: {type: BulletList, content: "list_item+", group: listGroup},
    list_item: {type: ListItem, content: itemContent}
  })
}
exports.addListNodes = addListNodes

// !! This module exports a number of list-related commands, which
// assume lists to be nestable, but with the restriction that the
// first child of a list item is not a list.

// :: (NodeType, ?Object) → (state: EditorState, onAction: ?(action: Action)) → bool
// Returns a command function that wraps the selection in a list with
// the given type an attributes. If `apply` is `false`, only return a
// value to indicate whether this is possible, but don't actually
// perform the change.
function wrapInList(nodeType, attrs) {
  return function(state, onAction) {
    let {$from, $to} = state.selection
    let range = $from.blockRange($to), doJoin = false, outerRange = range
    // This is at the top of an existing list item
    if (range.depth >= 2 && $from.node(range.depth - 1).type.compatibleContent(nodeType) && range.startIndex == 0) {
      // Don't do anything if this is the top of the list
      if ($from.index(range.depth - 1) == 0) return false
      let $insert = state.doc.resolve(range.start - 2)
      outerRange = new NodeRange($insert, $insert, range.depth)
      if (range.endIndex < range.parent.childCount)
        range = new NodeRange($from, state.doc.resolve($to.end(range.depth)), range.depth)
      doJoin = true
    }
    let wrap = findWrapping(outerRange, nodeType, attrs, range)
    if (!wrap) return false
    if (onAction) onAction(doWrapInList(state.tr, range, wrap, doJoin, nodeType).scrollAction())
    return true
  }
}
exports.wrapInList = wrapInList

function doWrapInList(tr, range, wrappers, joinBefore, nodeType) {
  let content = Fragment.empty
  for (let i = wrappers.length - 1; i >= 0; i--)
    content = Fragment.from(wrappers[i].type.create(wrappers[i].attrs, content))

  tr.step(new ReplaceAroundStep(range.start - (joinBefore ? 2 : 0), range.end, range.start, range.end,
                                new Slice(content, 0, 0), wrappers.length, true))

  let found = 0
  for (let i = 0; i < wrappers.length; i++) if (wrappers[i].type == nodeType) found = i + 1
  let splitDepth = wrappers.length - found

  let splitPos = range.start + wrappers.length - (joinBefore ? 2 : 0), parent = range.parent
  for (let i = range.startIndex, e = range.endIndex, first = true; i < e; i++, first = false) {
    if (!first && canSplit(tr.doc, splitPos, splitDepth)) tr.split(splitPos, splitDepth)
    splitPos += parent.child(i).nodeSize + (first ? 0 : 2 * splitDepth)
  }
  return tr
}

// :: (NodeType) → (state: EditorState) → bool
// Build a command that splits a non-empty textblock at the top level
// of a list item by also splitting that list item.
function splitListItem(nodeType) {
  return function(state, onAction) {
    let {$from, $to, node} = state.selection
    if ((node && node.isBlock) || !$from.parent.content.size ||
        $from.depth < 2 || !$from.sameParent($to)) return false
    let grandParent = $from.node(-1)
    if (grandParent.type != nodeType) return false
    let nextType = $to.pos == $from.end() ? grandParent.defaultContentType($from.indexAfter(-1)) : null
    let tr = state.tr.delete($from.pos, $to.pos)
    if (!canSplit(tr.doc, $from.pos, 2, nextType)) return false
    if (onAction) onAction(tr.split($from.pos, 2, nextType).scrollAction())
    return true
  }
}
exports.splitListItem = splitListItem

// :: (NodeType) → (state: EditorState, onAction: ?(action: Action)) → bool
// Create a command to lift the list item around the selection up into
// a wrapping list.
function liftListItem(nodeType) {
  return function(state, onAction) {
    let {$from, $to} = state.selection
    let range = $from.blockRange($to, node => node.childCount && node.firstChild.type == nodeType)
    if (!range || range.depth < 2 || $from.node(range.depth - 1).type != nodeType) return false
    if (onAction) {
      let tr = state.tr, end = range.end, endOfList = $to.end(range.depth)
      if (end < endOfList) {
        // There are siblings after the lifted items, which must become
        // children of the last item
        tr.step(new ReplaceAroundStep(end - 1, endOfList, end, endOfList,
                                      new Slice(Fragment.from(nodeType.create(null, range.parent.copy())), 1, 0), 1, true))
        range = new NodeRange(tr.doc.resolveNoCache($from.pos), tr.doc.resolveNoCache(endOfList), range.depth)
      }
      onAction(tr.lift(range, liftTarget(range)).scrollAction())
    }
    return true
  }
}
exports.liftListItem = liftListItem

// :: (NodeType) → (state: EditorState, onAction: ?(action: Action)) → bool
// Create a command to sink the list item around the selection down
// into an inner list.
function sinkListItem(nodeType) {
  return function(state, onAction) {
    let {$from, $to} = state.selection
    let range = $from.blockRange($to, node => node.childCount && node.firstChild.type == nodeType)
    if (!range) return false
    let startIndex = range.startIndex
    if (startIndex == 0) return false
    let parent = range.parent, nodeBefore = parent.child(startIndex - 1)
    if (nodeBefore.type != nodeType) return false

    if (onAction) {
      let nestedBefore = nodeBefore.lastChild && nodeBefore.lastChild.type == parent.type
      let inner = Fragment.from(nestedBefore ? nodeType.create() : null)
      let slice = new Slice(Fragment.from(nodeType.create(null, Fragment.from(parent.copy(inner)))),
                            nestedBefore ? 3 : 1, 0)
      let before = range.start, after = range.end
      onAction(state.tr.step(new ReplaceAroundStep(before - (nestedBefore ? 3 : 1), after,
                                                   before, after, slice, 1, true))
               .scrollAction())
    }
    return true
  }
}
exports.sinkListItem = sinkListItem
<|endoftext|>